diff --git a/azure-functions-maven-plugin/CHANGELOG.md b/azure-functions-maven-plugin/CHANGELOG.md
index 04be11bbd9..61ac4bf198 100644
--- a/azure-functions-maven-plugin/CHANGELOG.md
+++ b/azure-functions-maven-plugin/CHANGELOG.md
@@ -22,6 +22,11 @@ All notable changes to the "Maven Plugin for Azure Function" will be documented
- [1.2.1](#121)
- [1.2.0](#120)
+## 1.14.0
+- Support default value for region/pricing tier/javaVersion [#1755](https://github.com/microsoft/azure-maven-plugins/pull/1761)
+- Support username and password in proxy [#1677](https://github.com/microsoft/azure-maven-plugins/pull/1677)
+- Fix warning message of `illegal reflective access from groovy` [#1763](https://github.com/microsoft/azure-maven-plugins/pull/1763)
+
## 1.13.0
- Support skip function extensions installation [#1616](https://github.com/microsoft/azure-maven-plugins/issues/1616) (Thanks @sschmeck)
diff --git a/azure-functions-maven-plugin/pom.xml b/azure-functions-maven-plugin/pom.xml
index c28f476245..293a4b1c12 100644
--- a/azure-functions-maven-plugin/pom.xml
+++ b/azure-functions-maven-plugin/pom.xml
@@ -6,11 +6,11 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
azure-functions-maven-plugin
- 1.14.0-SNAPSHOT
+ 1.14.0
maven-plugin
Maven Plugin for Azure Functions
Maven Plugin for Azure Functions
@@ -52,22 +52,17 @@
provided
- com.squareup.okhttp3
- okhttp
-
-
- org.jetbrains.kotlin
- kotlin-stdlib
-
-
+ io.projectreactor.netty
+ reactor-netty
- com.squareup.okhttp3
- logging-interceptor
+ com.azure
+ azure-core-http-netty
- com.squareup.okhttp3
- okhttp-urlconnection
+ org.projectlombok
+ lombok
+ provided
com.microsoft.azure
@@ -173,6 +168,12 @@
azure-eventhubs-eph
test
+
+ com.microsoft.azure
+ azure
+ 1.41.1
+ test
+
org.jacoco
org.jacoco.agent
@@ -275,6 +276,56 @@
+
+
+
+ com.nickwongdev
+ aspectj-maven-plugin
+
+ false
+ 1.8
+ 1.8
+ ignore
+ 1.8
+ UTF-8
+ false
+ true
+ true
+
+
+
+ com.microsoft.azure
+ azure-toolkit-common-lib
+
+
+
+
+
+ compile-with-aspectj
+ process-classes
+
+
+ ${project.build.directory}/classes
+
+
+
+ compile
+
+
+
+ test-compile-with-aspectj
+ process-test-classes
+
+
+ ${project.build.directory}/test-classes
+
+
+
+ test-compile
+
+
+
+
org.apache.maven.plugins
maven-plugin-plugin
@@ -304,7 +355,6 @@
-
org.jacoco
jacoco-maven-plugin
diff --git a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/cleanup.groovy b/azure-functions-maven-plugin/src/it/3-eventhub-trigger/cleanup.groovy
deleted file mode 100644
index 2e5b53b5e4..0000000000
--- a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/cleanup.groovy
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- */
-
-import com.microsoft.azure.maven.function.invoker.storage.EventHubProcesser
-import com.microsoft.azure.maven.function.invoker.CommonUtils
-
-String storageName = "cihub${timestamp}"
-String namespaceName = "FunctionCIEventHubNamespace-${timestamp}"
-String resourceGroupName = "maven-functions-it-${timestamp}-rg-3"
-
-EventHubProcesser eventHubProcesser = null
-try {
- eventHubProcesser = new EventHubProcesser(resourceGroupName, namespaceName, storageName);
- // verify
- CommonUtils.runVerification(new Runnable() {
- @Override
- void run() {
- eventHubProcesser.sendMessageToEventHub("trigger", "CIInput")
- sleep(10 * 1000 /* ms */)
- assert eventHubProcesser.getMessageFromEventHub("output").get(0) == "CITest"
- }
- })
-} finally {
- if (eventHubProcesser != null) {
- eventHubProcesser.close()
- }
-}
-CommonUtils.deleteAzureResourceGroup(resourceGroupName, false)
-return true
-
diff --git a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/pom.xml b/azure-functions-maven-plugin/src/it/3-eventhub-trigger/pom.xml
deleted file mode 100644
index 630fe4ee77..0000000000
--- a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/pom.xml
+++ /dev/null
@@ -1,115 +0,0 @@
-
-
- 4.0.0
-
- com.microsoft.azure
- azure-java-functions
- 1.0-SNAPSHOT
- jar
-
- Azure Java Functions
-
-
- UTF-8
- 1.8
- 1.8
- maven-functions-it-${timestamp}-3
- westus
- ${project.build.directory}/azure-functions/${functionAppName}
- maven-functions-it-${timestamp}-rg-3
-
-
-
-
- com.microsoft.azure.functions
- azure-functions-java-library
- 1.2.0
-
-
- com.microsoft.azure
- azure-eventhubs
- 1.2.0
-
-
- com.microsoft.azure
- azure-eventhubs-eph
- 2.0.1
-
-
- com.microsoft.azure
- azure
- 1.18.0
-
-
- org.codehaus.plexus
- plexus-utils
- 3.0.20
-
-
-
-
-
-
-
- maven-resources-plugin
- 3.0.2
-
-
- @project.groupId@
- @project.artifactId@
- @project.version@
-
-
-
-
-
-
- @project.groupId@
- @project.artifactId@
-
-
- azure-auth
-
- ${functionResourceGroup}
- ${functionAppName}
- ${functionAppRegion}
-
-
-
- package-functions
-
- package
-
-
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
- 3.0.2
-
-
- copy-dependencies
- prepare-package
-
- copy-dependencies
-
-
- ${stagingDirectory}/lib
- false
- false
- true
- runtime
- azure-functions-java-library
-
-
-
-
-
-
-
-
-
-
diff --git a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/setup.groovy b/azure-functions-maven-plugin/src/it/3-eventhub-trigger/setup.groovy
deleted file mode 100644
index a7ad21f1df..0000000000
--- a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/setup.groovy
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- */
-
-import com.microsoft.azure.maven.function.invoker.CommonUtils
-import com.microsoft.azure.maven.function.invoker.storage.EventHubProcesser
-
-String functionName = "maven-functions-it-${timestamp}-3"
-String storageName = "cihub${timestamp}"
-String namespaceName = "FunctionCIEventHubNamespace-${timestamp}"
-String resourceGroupName = "maven-functions-it-${timestamp}-rg-3"
-
-CommonUtils.azureLogin()
-CommonUtils.deleteAzureResourceGroup(resourceGroupName, true)
-
-// Create EventHub
-EventHubProcesser eventHubProcesser = null
-eventHubProcesser = new EventHubProcesser(resourceGroupName, namespaceName, storageName);
-eventHubProcesser.createOrGetEventHubByName("trigger")
-eventHubProcesser.createOrGetEventHubByName("output")
-
-// Get connnection string of EventHub and save it to pom
-def connectionString = eventHubProcesser.getEventHubConnectionString()
-
-// Create FunctionApp and set eventhub connection string
-CommonUtils.executeCommand("az functionapp create --resource-group ${resourceGroupName} --consumption-plan-location westus " +
- "--name ${functionName} --storage-account ${storageName}")
-
-CommonUtils.executeCommand("az webapp config appsettings set --name ${functionName} --resource-group ${resourceGroupName} --settings CIEventHubConnection=\"${connectionString}\"")
-
-return true
-
diff --git a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/src/main/java/com/microsoft/azure/EventHubTriggerJava.java b/azure-functions-maven-plugin/src/it/3-eventhub-trigger/src/main/java/com/microsoft/azure/EventHubTriggerJava.java
deleted file mode 100644
index 53b39057ae..0000000000
--- a/azure-functions-maven-plugin/src/it/3-eventhub-trigger/src/main/java/com/microsoft/azure/EventHubTriggerJava.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.microsoft.azure;
-
-import com.microsoft.azure.functions.annotation.*;
-import com.microsoft.azure.functions.*;
-
-/**
- * Azure Functions with Event Hub trigger.
- */
-public class EventHubTriggerJava {
- /**
- * This function will be invoked when an event is received from Event Hub.
- */
- @FunctionName("EventHubTriggerJava")
- public void run(
- @EventHubTrigger(name = "message", eventHubName = "trigger", connection = "CIEventHubConnection", consumerGroup = "$Default") String message,
- @EventHubOutput(name = "result", eventHubName = "output", connection = "CIEventHubConnection") OutputBinding result,
- final ExecutionContext context
- ) {
- if(message.contains("CIInput")) {
- result.setValue("CITest");
- }
- }
-}
diff --git a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AbstractFunctionMojo.java b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AbstractFunctionMojo.java
index ad7842d829..f85356cd0c 100644
--- a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AbstractFunctionMojo.java
+++ b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/AbstractFunctionMojo.java
@@ -6,9 +6,9 @@
package com.microsoft.azure.maven.function;
import com.microsoft.azure.maven.AbstractAppServiceMojo;
-import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionApp;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.legacy.function.configurations.RuntimeConfiguration;
+import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugins.annotations.Parameter;
@@ -44,6 +44,7 @@ public abstract class AbstractFunctionMojo extends AbstractAppServiceMojo {
* P3V2
*
*/
+ @Getter
@Parameter(property = "functions.pricingTier")
protected String pricingTier;
@@ -64,7 +65,7 @@ public abstract class AbstractFunctionMojo extends AbstractAppServiceMojo {
/**
* App Service region, which will only be used to create App Service at the first time.
*/
- @Parameter(property = "functions.region", defaultValue = "westeurope")
+ @Parameter(property = "functions.region")
protected String region;
@Parameter(property = "functions.runtime")
@@ -79,6 +80,9 @@ public abstract class AbstractFunctionMojo extends AbstractAppServiceMojo {
@Parameter(property = "functions.disableAppInsights", defaultValue = "false")
protected boolean disableAppInsights;
+ @Getter
+ protected ConfigParser parser = new ConfigParser(this);
+
//endregion
//region Getter
@@ -108,10 +112,6 @@ public boolean isDisableAppInsights() {
return disableAppInsights;
}
- public IFunctionApp getFunctionApp() {
- return getOrCreateAzureAppServiceClient().functionApp(getResourceGroup(), getAppName());
- }
-
public RuntimeConfiguration getRuntimeConfiguration() {
return runtime;
}
diff --git a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/ConfigParser.java b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/ConfigParser.java
new file mode 100644
index 0000000000..a00c05b60b
--- /dev/null
+++ b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/ConfigParser.java
@@ -0,0 +1,78 @@
+/*
+ * 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.maven.function;
+
+import com.microsoft.azure.maven.MavenDockerCredentialProvider;
+import com.microsoft.azure.toolkit.lib.appservice.config.FunctionAppConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig;
+import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
+import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
+import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
+import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+import com.microsoft.azure.toolkit.lib.legacy.appservice.DeploymentSlotSetting;
+import com.microsoft.azure.toolkit.lib.legacy.function.configurations.RuntimeConfiguration;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+public class ConfigParser {
+ private final AbstractFunctionMojo mojo;
+
+ public ConfigParser(AbstractFunctionMojo mojo) {
+ this.mojo = mojo;
+ }
+
+ public FunctionAppConfig parseConfig() throws AzureExecutionException {
+ return (FunctionAppConfig) new FunctionAppConfig()
+ .disableAppInsights(mojo.isDisableAppInsights())
+ .appInsightsKey(mojo.getAppInsightsKey())
+ .appInsightsInstance(mojo.getAppInsightsInstance())
+ .subscriptionId(mojo.getSubscriptionId())
+ .resourceGroup(mojo.getResourceGroup())
+ .appName(mojo.getAppName())
+ .servicePlanName(mojo.getAppServicePlanName())
+ .servicePlanResourceGroup(mojo.getAppServicePlanResourceGroup())
+ .deploymentSlotName(getDeploymentSlotName())
+ .deploymentSlotConfigurationSource(getDeploymentSlotConfigurationSource())
+ .pricingTier(getParsedPricingTier())
+ .region(getParsedRegion())
+ .runtime(getRuntimeConfig())
+ .appSettings(mojo.getAppSettings());
+ }
+
+ public RuntimeConfig getRuntimeConfig() throws AzureExecutionException {
+ final RuntimeConfiguration runtime = mojo.getRuntimeConfiguration();
+ if (runtime == null) {
+ return null;
+ }
+ final OperatingSystem os = Optional.ofNullable(runtime.getOs()).map(OperatingSystem::fromString).orElse(null);
+ final JavaVersion javaVersion = Optional.ofNullable(runtime.getJavaVersion()).map(JavaVersion::fromString).orElse(null);
+ final RuntimeConfig result = new RuntimeConfig().os(os).javaVersion(javaVersion).webContainer(WebContainer.JAVA_OFF)
+ .image(runtime.getImage()).registryUrl(runtime.getRegistryUrl());
+ if (StringUtils.isNotEmpty(runtime.getServerId())) {
+ final MavenDockerCredentialProvider credentialProvider = MavenDockerCredentialProvider.fromMavenSettings(mojo.getSettings(), runtime.getServerId());
+ result.username(credentialProvider.getUsername()).password(credentialProvider.getPassword());
+ }
+ return result;
+ }
+
+ private String getDeploymentSlotName() {
+ return Optional.ofNullable(mojo.getDeploymentSlotSetting()).map(DeploymentSlotSetting::getName).orElse(null);
+ }
+
+ private String getDeploymentSlotConfigurationSource() {
+ return Optional.ofNullable(mojo.getDeploymentSlotSetting()).map(DeploymentSlotSetting::getConfigurationSource).orElse(null);
+ }
+
+ private Region getParsedRegion() {
+ return Optional.ofNullable(mojo.getRegion()).map(Region::fromName).orElse(null);
+ }
+
+ private PricingTier getParsedPricingTier() {
+ return Optional.ofNullable(mojo.getPricingTier()).map(PricingTier::fromString).orElse(null);
+ }
+}
diff --git a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/DeployMojo.java b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/DeployMojo.java
index fb5d8a2948..cfc66c6b8b 100644
--- a/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/DeployMojo.java
+++ b/azure-functions-maven-plugin/src/main/java/com/microsoft/azure/maven/function/DeployMojo.java
@@ -5,128 +5,54 @@
package com.microsoft.azure.maven.function;
-import com.azure.core.management.AzureEnvironment;
-import com.azure.core.management.exception.ManagementException;
-import com.microsoft.azure.functions.annotation.AuthorizationLevel;
-import com.microsoft.azure.maven.MavenDockerCredentialProvider;
import com.microsoft.azure.toolkit.lib.Azure;
-import com.microsoft.azure.toolkit.lib.applicationinsights.ApplicationInsights;
-import com.microsoft.azure.toolkit.lib.applicationinsights.ApplicationInsightsEntity;
import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
-import com.microsoft.azure.toolkit.lib.appservice.entity.AppServiceBaseEntity;
-import com.microsoft.azure.toolkit.lib.appservice.entity.FunctionEntity;
-import com.microsoft.azure.toolkit.lib.appservice.model.DockerConfiguration;
+import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.FunctionAppConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig;
import com.microsoft.azure.toolkit.lib.appservice.model.FunctionDeployType;
import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
-import com.microsoft.azure.toolkit.lib.appservice.model.Runtime;
-import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppServiceUpdater;
import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionApp;
import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionAppBase;
-import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionAppDeploymentSlot;
-import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
+import com.microsoft.azure.toolkit.lib.appservice.task.CreateOrUpdateFunctionAppTask;
+import com.microsoft.azure.toolkit.lib.appservice.task.DeployFunctionAppTask;
+import com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils;
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.model.Region;
-import com.microsoft.azure.toolkit.lib.common.model.ResourceGroup;
+import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.utils.Utils;
-import com.microsoft.azure.toolkit.lib.legacy.appservice.DeploymentSlotSetting;
-import com.microsoft.azure.toolkit.lib.resource.AzureGroup;
-import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.artifact.versioning.ComparableVersion;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
-import org.zeroturnaround.zip.ZipUtil;
-import reactor.core.publisher.Mono;
-import reactor.core.scheduler.Schedulers;
-import reactor.util.retry.Retry;
import java.io.File;
-import java.time.Duration;
import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
-import java.util.Properties;
-import java.util.stream.Collectors;
+
+import static com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils.fromAppService;
+import static com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils.mergeAppServiceConfig;
/**
* Deploy artifacts to target Azure Functions in Azure. If target Azure Functions doesn't exist, it will be created.
*/
@Mojo(name = "deploy", defaultPhase = LifecyclePhase.DEPLOY)
public class DeployMojo extends AbstractFunctionMojo {
-
- private static final String DEPLOY_START = "Starting deployment...";
- private static final String DEPLOY_FINISH =
- "Deployment done, you may access your resource through %s";
- private static final String FUNCTION_SLOT_CREATE_START = "The specified function slot does not exist. " +
- "Creating a new slot...";
- private static final String FUNCTION_SLOT_CREATED = "Successfully created the function slot: %s.";
- private static final String FUNCTION_SLOT_UPDATE = "Updating the specified function slot...";
- private static final String FUNCTION_SLOT_UPDATE_DONE = "Successfully updated the function slot: %s.";
- private static final String APPINSIGHTS_INSTRUMENTATION_KEY = "APPINSIGHTS_INSTRUMENTATIONKEY";
private static final String APPLICATION_INSIGHTS_CONFIGURATION_CONFLICT = "Contradictory configurations for application insights," +
" specify 'appInsightsKey' or 'appInsightsInstance' if you want to enable it, and specify " +
"'disableAppInsights=true' if you want to disable it.";
- private static final String FAILED_TO_GET_APPLICATION_INSIGHTS = "The application insights %s cannot be found, " +
- "will create it in resource group %s.";
- private static final String SKIP_CREATING_APPLICATION_INSIGHTS = "Skip creating application insights";
- private static final String APPLICATION_INSIGHTS_CREATE_START = "Creating application insights...";
- private static final String APPLICATION_INSIGHTS_CREATED = "Successfully created the application insights %s " +
- "for this Function App. You can visit %s/#@/resource%s/overview to view your " +
- "Application Insights component.";
- private static final String APPLICATION_INSIGHTS_CREATE_FAILED = "Unable to create the Application Insights " +
- "for the Function App due to error %s. Please use the Azure Portal to manually create and configure the " +
- "Application Insights if needed.";
- private static final String INSTRUMENTATION_KEY_IS_NOT_VALID = "Instrumentation key is not valid, " +
- "please update the application insights configuration";
- private static final String UNABLE_TO_LIST_NONE_ANONYMOUS_HTTP_TRIGGERS = "Some http trigger urls cannot be displayed " +
- "because they are non-anonymous. To access the non-anonymous triggers, please refer to https://aka.ms/azure-functions-key.";
- private static final String HTTP_TRIGGER_URLS = "HTTP Trigger Urls:";
- private static final String NO_ANONYMOUS_HTTP_TRIGGER = "No anonymous HTTP Triggers found in deployed function app, skip list triggers.";
- private static final String AUTH_LEVEL = "authLevel";
- private static final String HTTP_TRIGGER = "httpTrigger";
private static final String ARTIFACT_INCOMPATIBLE_WARNING = "Your function app artifact compile version {0} may not compatible with java version {1} in " +
"configuration.";
private static final String ARTIFACT_INCOMPATIBLE_ERROR = "Your function app artifact compile version {0} is not compatible with java version {1} in " +
"configuration, please downgrade the project compile version and try again.";
- private static final String FUNCTIONS_WORKER_RUNTIME_NAME = "FUNCTIONS_WORKER_RUNTIME";
- private static final String FUNCTIONS_WORKER_RUNTIME_VALUE = "java";
- private static final String SET_FUNCTIONS_WORKER_RUNTIME = "Set function worker runtime to java.";
- private static final String CUSTOMIZED_FUNCTIONS_WORKER_RUNTIME_WARNING = "App setting `FUNCTIONS_WORKER_RUNTIME` doesn't " +
- "meet the requirement of Azure Java Functions, the value should be `java`.";
- private static final String FUNCTIONS_EXTENSION_VERSION_NAME = "FUNCTIONS_EXTENSION_VERSION";
- private static final String FUNCTIONS_EXTENSION_VERSION_VALUE = "~3";
- private static final String SET_FUNCTIONS_EXTENSION_VERSION = "Functions extension version " +
- "isn't configured, setting up the default value.";
- private static final String RUNNING = "Running";
- private static final String CREATE_FUNCTION_APP = "Creating function app %s...";
- private static final String CREATE_FUNCTION_APP_DONE = "Successfully created function app %s.";
- private static final String CREATE_APP_SERVICE_PLAN = "Creating app service plan...";
- private static final String CREATE_APP_SERVICE_DONE = "Successfully created app service plan %s.";
- private static final String CREATE_RESOURCE_GROUP = "Creating resource group %s in region %s...";
- private static final String CREATE_RESOURCE_GROUP_DONE = "Successfully created resource group %s.";
- private static final String CREATE_NEW_FUNCTION_APP = "isCreateNewFunctionApp";
- private static final String CREATE_NEW_APP_SERVICE_PLAN = "createNewAppServicePlan";
- private static final String CREATE_NEW_RESOURCE_GROUP = "createNewResourceGroup";
- private static final String UPDATE_FUNCTION_APP = "Updating target Function App %s...";
- private static final String UPDATE_FUNCTION_DONE = "Successfully updated Function App %s.";
private static final String NO_ARTIFACT_FOUNDED = "Failed to find function artifact '%s.jar' in folder '%s', please re-package the project and try again.";
- private static final String LOCAL_SETTINGS_FILE = "local.settings.json";
- private static final int LIST_TRIGGERS_MAX_RETRY = 5;
- private static final int LIST_TRIGGERS_RETRY_PERIOD_IN_SECONDS = 10;
- private static final String SYNCING_TRIGGERS = "Syncing triggers and fetching function information";
- private static final String SYNCING_TRIGGERS_WITH_RETRY = "Syncing triggers and fetching function information (Attempt {0}/{1})...";
- private static final String NO_TRIGGERS_FOUNDED = "No triggers found in deployed function app, " +
- "please try recompile the project by `mvn clean package` and deploy again.";
private static final String APP_NAME_PATTERN = "[a-zA-Z0-9\\-]{2,60}";
private static final String RESOURCE_GROUP_PATTERN = "[a-zA-Z0-9._\\-()]{1,90}";
private static final String SLOT_NAME_PATTERN = "[A-Za-z0-9-]{1,60}";
@@ -143,29 +69,21 @@ public class DeployMojo extends AbstractFunctionMojo {
private static final String INVALID_SLOT_NAME = "Invalid value of inside in pom.xml, it needs to match the pattern '%s'";
private static final String EMPTY_IMAGE_NAME = "Please config the of in pom.xml.";
private static final String INVALID_OS = "The value of is not correct, supported values are: windows, linux and docker.";
- private static final String FAILED_TO_LIST_TRIGGERS = "Deployment succeeded, but failed to list http trigger urls.";
- private static final String SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE = "Skip deployment for docker app service";
private static final String EXPANDABLE_PRICING_TIER_WARNING = "'%s' may not be a valid pricing tier, " +
"please refer to https://aka.ms/maven_function_configuration#supported-pricing-tiers for valid values";
private static final String EXPANDABLE_REGION_WARNING = "'%s' may not be a valid region, " +
"please refer to https://aka.ms/maven_function_configuration#supported-regions for valid values";
private static final String EXPANDABLE_JAVA_VERSION_WARNING = "'%s' may not be a valid java version, recommended values are `Java 8` and `Java 11`";
- private AzureAppService az;
-
@Override
+ @AzureOperation(name = "functionapp|mojo.deploy", type = AzureOperation.Type.ACTION)
protected void doExecute() throws AzureExecutionException {
doValidate();
- processAppSettingsWithDefaultValue();
-
- az = getOrCreateAzureAppServiceClient();
- final IFunctionAppBase extends AppServiceBaseEntity> target = createOrUpdateResource();
+ getOrCreateAzureAppServiceClient();
+ final IFunctionAppBase> target = createOrUpdateResource(getParser().parseConfig());
deployArtifact(target);
-
- if (target instanceof IFunctionApp) {
- listHTTPTriggerUrls((IFunctionApp) target);
- }
+ updateTelemetryProperties();
}
protected void doValidate() throws AzureExecutionException {
@@ -228,256 +146,55 @@ protected void validateParameters() {
}
}
- protected IFunctionAppBase extends AppServiceBaseEntity> createOrUpdateResource() throws AzureExecutionException {
- final String deploymentSlotName = Optional.ofNullable(deploymentSlotSetting)
- .map(DeploymentSlotSetting::getName).orElse(null);
- final IFunctionApp functionApp = az.functionApp(getResourceGroup(), getAppName());
- if (StringUtils.isEmpty(deploymentSlotName)) {
- return functionApp.exists() ? updateFunctionApp(functionApp) : createFunctionApp(functionApp);
- } else {
- final IFunctionAppDeploymentSlot slot = functionApp.deploymentSlot(deploymentSlotName);
- return slot.exists() ? updateDeploymentSlot(slot) : createDeploymentSlot(slot);
- }
- }
-
- protected IFunctionApp createFunctionApp(final IFunctionApp functionApp) throws AzureExecutionException {
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_FUNCTION_APP, String.valueOf(true));
- final ResourceGroup resourceGroup = getOrCreateResourceGroup();
- final IAppServicePlan appServicePlan = getOrCreateAppServicePlan();
- AzureMessager.getMessager().info(String.format(CREATE_FUNCTION_APP, getAppName()));
- final Runtime runtime = getRuntimeOrDefault();
- final Map appSettings = getAppSettings();
- // get/create ai instances only if user didn't specify ai connection string in app settings
- bindApplicationInsights(appSettings, true);
- final IFunctionApp result = functionApp.create().withName(getAppName())
- .withResourceGroup(resourceGroup.getName())
- .withPlan(appServicePlan.id())
- .withRuntime(runtime)
- .withDockerConfiguration(getDockerConfiguration())
- .withAppSettings(appSettings)
- .commit();
- AzureMessager.getMessager().info(String.format(CREATE_FUNCTION_APP_DONE, result.name()));
- return result;
- }
-
- private IAppServicePlan getOrCreateAppServicePlan() {
- final String servicePlanName = StringUtils.isEmpty(getAppServicePlanName()) ?
- String.format("asp-%s", getAppName()) : getAppServicePlanName();
- final String servicePlanGroup = getServicePlanResourceGroup();
- final IAppServicePlan appServicePlan = az.appServicePlan(servicePlanGroup, servicePlanName);
- if (!appServicePlan.exists()) {
- AzureMessager.getMessager().info(CREATE_APP_SERVICE_PLAN);
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_APP_SERVICE_PLAN, String.valueOf(true));
- appServicePlan.create()
- .withName(servicePlanName)
- .withResourceGroup(servicePlanGroup)
- .withRegion(getParsedRegion())
- .withPricingTier(getParsedPricingTier())
- .withOperatingSystem(getRuntimeOrDefault().getOperatingSystem())
- .commit();
- AzureMessager.getMessager().info(String.format(CREATE_APP_SERVICE_DONE, appServicePlan.name()));
- }
- return appServicePlan;
- }
-
- private Region getParsedRegion() {
- return Optional.ofNullable(region).map(Region::fromName).orElse(Region.US_WEST);
- }
-
- private PricingTier getParsedPricingTier() {
- if (StringUtils.isEmpty(pricingTier)) {
- return PricingTier.CONSUMPTION;
- }
- return Optional.ofNullable(PricingTier.fromString(pricingTier))
- .orElseThrow(() -> new AzureToolkitRuntimeException(String.format("Invalid pricing tier %s", pricingTier)));
- }
-
- private ResourceGroup getOrCreateResourceGroup() {
- try {
- return Azure.az(AzureGroup.class).getByName(getResourceGroup());
- } catch (ManagementException e) {
- AzureMessager.getMessager().info(String.format(CREATE_RESOURCE_GROUP, getResourceGroup(), getRegion()));
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_RESOURCE_GROUP, String.valueOf(true));
- final ResourceGroup result = Azure.az(AzureGroup.class).create(getResourceGroup(), getRegion());
- AzureMessager.getMessager().info(String.format(CREATE_RESOURCE_GROUP_DONE, result.getName()));
- return result;
+ protected IFunctionAppBase> createOrUpdateResource(final FunctionAppConfig config) {
+ IFunctionApp app = Azure.az(AzureAppService.class).functionApp(config.resourceGroup(), config.appName());
+ final boolean newFunctionApp = !app.exists();
+ AppServiceConfig defaultConfig = !newFunctionApp ? fromAppService(app, app.plan()) : buildDefaultConfig(config.subscriptionId(),
+ config.resourceGroup(), config.appName());
+ mergeAppServiceConfig(config, defaultConfig);
+ if (!newFunctionApp && !config.disableAppInsights() && StringUtils.isEmpty(config.appInsightsKey())) {
+ // fill ai key from existing app settings
+ config.appInsightsKey(app.entity().getAppSettings().get(CreateOrUpdateFunctionAppTask.APPINSIGHTS_INSTRUMENTATION_KEY));
}
+ return new CreateOrUpdateFunctionAppTask(config).execute();
}
- private Runtime getRuntimeOrDefault() {
- final OperatingSystem os = Optional.ofNullable(runtime.getOs()).map(OperatingSystem::fromString).orElse(OperatingSystem.WINDOWS);
- final JavaVersion javaVersion = Optional.ofNullable(runtime.getJavaVersion()).map(JavaVersion::fromString).orElse(JavaVersion.JAVA_8);
- return Runtime.getRuntime(os, WebContainer.JAVA_OFF, javaVersion);
- }
-
- private Runtime getRuntime() {
- if (StringUtils.isEmpty(runtime.getOs()) && StringUtils.isEmpty(runtime.getJavaVersion())) {
- return null;
- }
- final OperatingSystem os = OperatingSystem.fromString(runtime.getOs());
- final JavaVersion javaVersion = JavaVersion.fromString(runtime.getJavaVersion());
- return Runtime.getRuntime(os, WebContainer.JAVA_OFF, javaVersion);
- }
-
- private DockerConfiguration getDockerConfiguration() throws AzureExecutionException {
- final OperatingSystem os = Optional.ofNullable(runtime.getOs()).map(OperatingSystem::fromString).orElse(null);
- if (os != OperatingSystem.DOCKER) {
- return null;
- }
- final MavenDockerCredentialProvider credentialProvider = MavenDockerCredentialProvider.fromMavenSettings(getSettings(), runtime.getServerId());
- return DockerConfiguration.builder()
- .registryUrl(runtime.getRegistryUrl())
- .image(runtime.getImage())
- .userName(credentialProvider.getUsername())
- .password(credentialProvider.getPassword()).build();
- }
-
- protected IFunctionApp updateFunctionApp(final IFunctionApp functionApp) throws AzureExecutionException {
- // update app service plan
- AzureMessager.getMessager().info(String.format(UPDATE_FUNCTION_APP, functionApp.name()));
- final IAppServicePlan currentPlan = functionApp.plan();
- IAppServicePlan targetServicePlan = StringUtils.isEmpty(appServicePlanName) ? currentPlan :
- az.appServicePlan(getServicePlanResourceGroup(), appServicePlanName);
- if (!targetServicePlan.exists()) {
- targetServicePlan = getOrCreateAppServicePlan();
- } else {
- if (region != null && !Objects.equals(Region.fromName(region), Region.fromName(targetServicePlan.entity().getRegion()))) {
- AzureMessager.getMessager().warning(String.format("Skip region update for existing service plan '%s' since it is not allowed.",
- targetServicePlan.name()));
- }
- if (StringUtils.isNotEmpty(pricingTier)) {
- targetServicePlan.update().withPricingTier(getParsedPricingTier()).commit();
+ private AppServiceConfig buildDefaultConfig(String subscriptionId, String resourceGroup, String appName) {
+ ComparableVersion javaVersionForProject = null;
+ final String outputFileName = project.getBuild().getFinalName() + "." + project.getPackaging();
+ File outputFile = new File(project.getBuild().getDirectory(), outputFileName);
+ if (outputFile.exists() && StringUtils.equalsIgnoreCase("jar", FilenameUtils.getExtension(outputFile.getName()))) {
+ try {
+ javaVersionForProject = new ComparableVersion(Utils.getArtifactCompileVersion(outputFile));
+ } catch (Exception e) {
+ // it is acceptable that java version from jar file cannot be retrieved
}
}
- // update app settings
- final Map appSettings = getAppSettings();
- final IAppServiceUpdater extends IFunctionApp> update = functionApp.update();
- if (isDisableAppInsights()) {
- update.withoutAppSettings(APPINSIGHTS_INSTRUMENTATION_KEY);
- } else {
- bindApplicationInsights(appSettings, false);
- }
- final IFunctionApp result = update.withPlan(targetServicePlan.id())
- .withRuntime(getRuntime())
- .withDockerConfiguration(getDockerConfiguration())
- .withAppSettings(appSettings)
- .commit();
- AzureMessager.getMessager().info(String.format(UPDATE_FUNCTION_DONE, functionApp.name()));
- return result;
- }
-
- private String getServicePlanResourceGroup() {
- return StringUtils.isEmpty(getAppServicePlanResourceGroup()) ? getResourceGroup() : getAppServicePlanResourceGroup();
- }
-
- protected IFunctionAppDeploymentSlot createDeploymentSlot(final IFunctionAppDeploymentSlot deploymentSlot)
- throws AzureExecutionException {
- AzureMessager.getMessager().info(FUNCTION_SLOT_CREATE_START);
- final DeploymentSlotSetting slotSetting = getDeploymentSlotSetting();
- final Map appSettings = getAppSettings();
- bindApplicationInsights(appSettings, false);
- final IFunctionAppDeploymentSlot result = deploymentSlot.create().withAppSettings(appSettings)
- .withConfigurationSource(slotSetting.getConfigurationSource())
- .withName(slotSetting.getName()).commit();
- AzureMessager.getMessager().info(String.format(FUNCTION_SLOT_CREATED, result.name()));
- return result;
- }
-
- protected IFunctionAppDeploymentSlot updateDeploymentSlot(final IFunctionAppDeploymentSlot deploymentSlot) throws AzureExecutionException {
- AzureMessager.getMessager().info(FUNCTION_SLOT_UPDATE);
- final Map appSettings = getAppSettings();
- final IFunctionAppDeploymentSlot.Updater update = deploymentSlot.update();
- // todo: remove duplicate codes with update function
- if (isDisableAppInsights()) {
- update.withoutAppSettings(APPINSIGHTS_INSTRUMENTATION_KEY);
- } else {
- bindApplicationInsights(appSettings, false);
- }
- final IFunctionAppDeploymentSlot result = update.withAppSettings(appSettings).commit();
- AzureMessager.getMessager().info(String.format(FUNCTION_SLOT_UPDATE_DONE, result.name()));
- return deploymentSlot;
- }
-
- private void deployArtifact(IFunctionAppBase extends AppServiceBaseEntity> target) throws AzureExecutionException {
- if (target.getRuntime().isDocker()) {
- AzureMessager.getMessager().info(SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE);
- return;
- }
- AzureMessager.getMessager().info(DEPLOY_START);
- final FunctionDeployType deployType = StringUtils.isEmpty(deploymentType) ? null : FunctionDeployType.fromString(deploymentType);
- // For ftp deploy, we need to upload entire staging directory not the zipped package
- final File file = deployType == FunctionDeployType.FTP ? new File(getDeploymentStagingDirectoryPath()) : packageStagingDirectory();
- final RunnableWithException deployRunnable = deployType == null ? () -> target.deploy(file) : () -> target.deploy(file, deployType);
- executeWithTimeRecorder(deployRunnable, DEPLOY);
- // todo: check function status after deployment
- if (!StringUtils.equalsIgnoreCase(target.state(), RUNNING)) {
- target.start();
- }
- AzureMessager.getMessager().info(String.format(DEPLOY_FINISH, getResourcePortalUrl(target.id())));
- }
-
- private File packageStagingDirectory() {
- final File zipFile = new File(getDeploymentStagingDirectoryPath() + ".zip");
- final File stagingDirectory = new File(getDeploymentStagingDirectoryPath());
-
- ZipUtil.pack(stagingDirectory, zipFile);
- ZipUtil.removeEntry(zipFile, LOCAL_SETTINGS_FILE);
- return zipFile;
- }
- /**
- * List anonymous HTTP Triggers url after deployment
- */
- protected void listHTTPTriggerUrls(IFunctionApp target) {
- try {
- final List triggers = listFunctions(target);
- final List httpFunction = triggers.stream()
- .filter(function -> function.getTrigger() != null &&
- StringUtils.equalsIgnoreCase(function.getTrigger().getType(), HTTP_TRIGGER))
- .collect(Collectors.toList());
- final List anonymousTriggers = httpFunction.stream()
- .filter(bindingResource -> bindingResource.getTrigger() != null &&
- StringUtils.equalsIgnoreCase(bindingResource.getTrigger().getProperty(AUTH_LEVEL), AuthorizationLevel.ANONYMOUS.toString()))
- .collect(Collectors.toList());
- if (CollectionUtils.isEmpty(httpFunction) || CollectionUtils.isEmpty(anonymousTriggers)) {
- AzureMessager.getMessager().info(NO_ANONYMOUS_HTTP_TRIGGER);
- return;
- }
- AzureMessager.getMessager().info(HTTP_TRIGGER_URLS);
- anonymousTriggers.forEach(trigger -> AzureMessager.getMessager().info(String.format("\t %s : %s", trigger.getName(), trigger.getTriggerUrl())));
- if (anonymousTriggers.size() < httpFunction.size()) {
- AzureMessager.getMessager().info(UNABLE_TO_LIST_NONE_ANONYMOUS_HTTP_TRIGGERS);
- }
- } catch (RuntimeException e) {
- // show warning instead of exception for list triggers
- AzureMessager.getMessager().warning(FAILED_TO_LIST_TRIGGERS);
- }
+ javaVersionForProject = ObjectUtils.firstNonNull(javaVersionForProject, new ComparableVersion(System.getProperty("java.version")));
+ // get java version according to project java version
+ JavaVersion javaVersion = javaVersionForProject.compareTo(new ComparableVersion("9")) < 0 ? JavaVersion.JAVA_8 : JavaVersion.JAVA_11;
+ return AppServiceConfigUtils.buildDefaultFunctionConfig(subscriptionId, resourceGroup, appName, javaVersion);
}
- private List listFunctions(final IFunctionApp functionApp) {
- final int[] count = {0};
- return Mono.fromCallable(() -> {
- final AzureString message = count[0]++ == 0 ?
- AzureString.fromString(SYNCING_TRIGGERS) : AzureString.format(SYNCING_TRIGGERS_WITH_RETRY, count[0], LIST_TRIGGERS_MAX_RETRY);
- AzureMessager.getMessager().info(message);
- return Optional.ofNullable(functionApp.listFunctions(true))
- .filter(CollectionUtils::isNotEmpty)
- .orElseThrow(() -> new AzureToolkitRuntimeException(NO_TRIGGERS_FOUNDED));
- }).subscribeOn(Schedulers.boundedElastic())
- .retryWhen(Retry.fixedDelay(LIST_TRIGGERS_MAX_RETRY - 1, Duration.ofSeconds(LIST_TRIGGERS_RETRY_PERIOD_IN_SECONDS))).block();
+ private void deployArtifact(final IFunctionAppBase> target) {
+ final File file = new File(getDeploymentStagingDirectoryPath());
+ final FunctionDeployType type = StringUtils.isEmpty(deploymentType) ? null : FunctionDeployType.fromString(deploymentType);
+ new DeployFunctionAppTask(target, file, type).execute();
}
protected void validateArtifactCompileVersion() throws AzureExecutionException {
- final Runtime runtime = getRuntimeOrDefault();
- if (runtime.isDocker()) {
+ final RuntimeConfig runtimeConfig = getParser().getRuntimeConfig();
+ if (runtimeConfig.os() == OperatingSystem.DOCKER) {
return;
}
- final ComparableVersion runtimeVersion = new ComparableVersion(runtime.getJavaVersion().getValue());
+ final JavaVersion javaVersion = Optional.ofNullable(runtimeConfig.javaVersion()).orElse(CreateOrUpdateFunctionAppTask.DEFAULT_FUNCTION_JAVA_VERSION);
+ final ComparableVersion runtimeVersion = new ComparableVersion(javaVersion.getValue());
final ComparableVersion artifactVersion = new ComparableVersion(Utils.getArtifactCompileVersion(getArtifactToDeploy()));
if (runtimeVersion.compareTo(artifactVersion) >= 0) {
return;
}
- if (runtime.getJavaVersion().isExpandedValue()) {
+ if (javaVersion.isExpandedValue()) {
AzureMessager.getMessager().warning(AzureString.format(ARTIFACT_INCOMPATIBLE_WARNING, artifactVersion.toString(), runtimeVersion.toString()));
} else {
final String errorMessage = AzureString.format(ARTIFACT_INCOMPATIBLE_ERROR, artifactVersion.toString(), runtimeVersion.toString()).toString();
@@ -485,30 +202,6 @@ protected void validateArtifactCompileVersion() throws AzureExecutionException {
}
}
- public void processAppSettingsWithDefaultValue() {
- if (appSettings == null) {
- appSettings = new Properties();
- }
- setDefaultAppSetting(appSettings, FUNCTIONS_WORKER_RUNTIME_NAME, SET_FUNCTIONS_WORKER_RUNTIME,
- FUNCTIONS_WORKER_RUNTIME_VALUE, CUSTOMIZED_FUNCTIONS_WORKER_RUNTIME_WARNING);
- setDefaultAppSetting(appSettings, FUNCTIONS_EXTENSION_VERSION_NAME, SET_FUNCTIONS_EXTENSION_VERSION,
- FUNCTIONS_EXTENSION_VERSION_VALUE, null);
- }
-
- private void setDefaultAppSetting(Map result, String settingName, String settingIsEmptyMessage,
- String defaultValue, String warningMessage) {
- final String setting = (String) result.get(settingName);
- if (StringUtils.isEmpty(setting)) {
- AzureMessager.getMessager().info(settingIsEmptyMessage);
- result.put(settingName, defaultValue);
- return;
- }
- // Show warning message when user set a different value
- if (!StringUtils.equalsIgnoreCase(setting, defaultValue) && StringUtils.isNotEmpty(warningMessage)) {
- AzureMessager.getMessager().warning(warningMessage);
- }
- }
-
private File getArtifactToDeploy() throws AzureExecutionException {
final File stagingFolder = new File(getDeploymentStagingDirectoryPath());
return Arrays.stream(Optional.ofNullable(stagingFolder.listFiles()).orElse(new File[0]))
@@ -517,73 +210,9 @@ private File getArtifactToDeploy() throws AzureExecutionException {
.orElseThrow(() -> new AzureExecutionException(String.format(NO_ARTIFACT_FOUNDED, this.getFinalName(), stagingFolder)));
}
- /**
- * Binding Function App with Application Insights
- * Will follow the below sequence appInsightsKey -> appInsightsInstance -> Create New AI Instance (Function creation only)
- *
- * @param appSettings App settings map
- * @param isCreation Define the stage of function app, as we only create ai instance by default when create new function apps
- * @throws AzureExecutionException When there are conflicts in configuration or meet errors while finding/creating application insights instance
- */
- private void bindApplicationInsights(Map appSettings, boolean isCreation) throws AzureExecutionException {
- // Skip app insights creation when user specify ai connection string in app settings
- if (appSettings.containsKey(APPINSIGHTS_INSTRUMENTATION_KEY)) {
- return;
- }
- final String instrumentationKey;
- if (StringUtils.isNotEmpty(getAppInsightsKey())) {
- instrumentationKey = getAppInsightsKey();
- if (!Utils.isGUID(instrumentationKey)) {
- throw new AzureExecutionException(INSTRUMENTATION_KEY_IS_NOT_VALID);
- }
- } else {
- final ApplicationInsightsEntity applicationInsightsComponent = getOrCreateApplicationInsights(isCreation);
- instrumentationKey = applicationInsightsComponent == null ? null : applicationInsightsComponent.getInstrumentationKey();
- }
- if (StringUtils.isNotEmpty(instrumentationKey)) {
- appSettings.put(APPINSIGHTS_INSTRUMENTATION_KEY, instrumentationKey);
- }
- }
-
private void validateApplicationInsightsConfiguration() throws AzureExecutionException {
if (isDisableAppInsights() && (StringUtils.isNotEmpty(getAppInsightsKey()) || StringUtils.isNotEmpty(getAppInsightsInstance()))) {
throw new AzureExecutionException(APPLICATION_INSIGHTS_CONFIGURATION_CONFLICT);
}
}
-
- private ApplicationInsightsEntity getOrCreateApplicationInsights(boolean enableCreation) {
- return StringUtils.isNotEmpty(getAppInsightsInstance()) ? getApplicationInsights(getAppInsightsInstance()) :
- enableCreation ? createApplicationInsights(getAppName()) : null;
- }
-
- private ApplicationInsightsEntity getApplicationInsights(String appInsightsInstance) {
- ApplicationInsightsEntity resource;
- try {
- resource = Azure.az(ApplicationInsights.class).get(getResourceGroup(), appInsightsInstance);
- } catch (ManagementException e) {
- resource = null;
- }
- if (resource == null) {
- AzureMessager.getMessager().warning(String.format(FAILED_TO_GET_APPLICATION_INSIGHTS, appInsightsInstance, getResourceGroup()));
- return createApplicationInsights(appInsightsInstance);
- }
- return resource;
- }
-
- private ApplicationInsightsEntity createApplicationInsights(String name) {
- if (isDisableAppInsights()) {
- AzureMessager.getMessager().info(SKIP_CREATING_APPLICATION_INSIGHTS);
- return null;
- }
- try {
- AzureMessager.getMessager().info(APPLICATION_INSIGHTS_CREATE_START);
- final AzureEnvironment environment = Azure.az(AzureAccount.class).account().getEnvironment();
- final ApplicationInsightsEntity resource = Azure.az(ApplicationInsights.class).create(getResourceGroup(), Region.fromName(getRegion()), name);
- AzureMessager.getMessager().info(String.format(APPLICATION_INSIGHTS_CREATED, resource.getName(), getPortalUrl(environment), resource.getId()));
- return resource;
- } catch (Exception e) {
- AzureMessager.getMessager().warning(String.format(APPLICATION_INSIGHTS_CREATE_FAILED, e.getMessage()));
- return null;
- }
- }
}
diff --git a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/DeployMojoTest.java b/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/DeployMojoTest.java
index 82fb86a4e9..d27035cd66 100644
--- a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/DeployMojoTest.java
+++ b/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/DeployMojoTest.java
@@ -5,17 +5,13 @@
package com.microsoft.azure.maven.function;
-import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
-import com.microsoft.azure.toolkit.lib.legacy.appservice.DeploymentSlotSetting;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
@RunWith(MockitoJUnitRunner.class)
@@ -38,16 +34,6 @@ public void getConfiguration() {
assertEquals("westeurope", mojo.getRegion());
}
- @Ignore
- @Test(expected = AzureExecutionException.class)
- public void testDeploymentSlotThrowExceptionIfFunctionNotExists() throws AzureExecutionException {
- final DeploymentSlotSetting slotSetting = new DeploymentSlotSetting();
- slotSetting.setName("Exception");
- doReturn(slotSetting).when(mojoSpy).getDeploymentSlotSetting();
- doReturn(null).when(mojoSpy).getFunctionApp();
- mojoSpy.doExecute();
- }
-
private DeployMojo getMojoFromPom() throws Exception {
final DeployMojo mojoFromPom = (DeployMojo) getMojoFromPom("/pom.xml", "deploy");
assertNotNull(mojoFromPom);
diff --git a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/invoker/storage/EventHubProcesser.java b/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/invoker/storage/EventHubProcesser.java
deleted file mode 100644
index 85abe8f100..0000000000
--- a/azure-functions-maven-plugin/src/test/java/com/microsoft/azure/maven/function/invoker/storage/EventHubProcesser.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.maven.function.invoker.storage;
-
-import com.google.gson.Gson;
-import com.microsoft.azure.eventhubs.ConnectionStringBuilder;
-import com.microsoft.azure.eventhubs.EventData;
-import com.microsoft.azure.eventhubs.EventHubClient;
-import com.microsoft.azure.eventhubs.EventPosition;
-import com.microsoft.azure.eventhubs.PartitionReceiver;
-import com.microsoft.azure.management.Azure;
-import com.microsoft.azure.management.eventhub.EventHub;
-import com.microsoft.azure.management.eventhub.EventHubNamespace;
-import com.microsoft.azure.management.resources.ResourceGroup;
-import com.microsoft.azure.management.resources.fluentcore.arm.Region;
-import com.microsoft.azure.management.storage.StorageAccount;
-import com.microsoft.azure.management.storage.StorageAccountSkuType;
-import com.microsoft.azure.maven.function.invoker.CommonUtils;
-
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-
-public class EventHubProcesser {
-
- private static final String SAS_KAY_NAME = "RootManageSharedAccessKey";
-
- private EventHubNamespace eventHubNamespace;
- private StorageAccount storageAccount;
- private ResourceGroup resourceGroup;
-
- private ScheduledExecutorService executorService = Executors.newScheduledThreadPool(8);
- private Map eventHubClientMap = new HashMap<>();
-
- public EventHubProcesser(String resourceGroupName, String namespaceName, String storageAccountName)
- throws Exception {
- final Azure azureClint = CommonUtils.getAzureClient();
-
- if (azureClint.resourceGroups().contain(resourceGroupName)) {
- resourceGroup = azureClint.resourceGroups().getByName(resourceGroupName);
- } else {
- resourceGroup = azureClint.resourceGroups().define(resourceGroupName).withRegion(Region.US_EAST).create();
- }
-
- final boolean isEventHubNamespaceExist = azureClint.eventHubNamespaces().list().stream()
- .anyMatch(namespace -> namespace.name().equals(namespaceName) &&
- namespace.resourceGroupName().equals(resourceGroupName));
- if (isEventHubNamespaceExist) {
- eventHubNamespace = azureClint.eventHubNamespaces().getByResourceGroup(resourceGroupName, namespaceName);
- } else {
- eventHubNamespace = azureClint.eventHubNamespaces()
- .define(namespaceName).withRegion(resourceGroup.region())
- .withExistingResourceGroup(resourceGroupName).create();
- }
-
- storageAccount = azureClint.storageAccounts().getByResourceGroup(resourceGroupName, storageAccountName);
- if (storageAccount == null) {
- storageAccount = azureClint.storageAccounts()
- .define(storageAccountName).withRegion(resourceGroup.region())
- .withExistingResourceGroup(resourceGroup)
- .withSku(StorageAccountSkuType.STANDARD_LRS)
- .withGeneralPurposeAccountKindV2().create();
- }
- }
-
- public EventHub createOrGetEventHubByName(final String eventHubName) throws Exception {
- final Azure azureClient = CommonUtils.getAzureClient();
- final Optional eventHub = eventHubNamespace.listEventHubs().stream()
- .filter(eventHubEntry -> eventHubEntry.name().equals(eventHubName)).findFirst();
- return eventHub.isPresent() ? eventHub.get() : azureClient.eventHubs().define(eventHubName)
- .withExistingNamespace(eventHubNamespace)
- .withExistingStorageAccountForCapturedData(storageAccount, eventHubName)
- .withDataCaptureEnabled().create();
- }
-
- public void sendMessageToEventHub(final String eventHubName, final String message) throws Exception {
- final EventHubClient eventHubClient = getEventHubClientByName(eventHubName);
- final Gson gson = new Gson();
- final byte[] payloadBytes = gson.toJson(message).getBytes(Charset.defaultCharset());
- final EventData sendEvent = EventData.create(payloadBytes);
- eventHubClient.send(sendEvent).get();
- }
-
- public List getMessageFromEventHub(final String eventHubName) throws Exception {
- final List result = new CopyOnWriteArrayList<>();
- final EventHubClient eventHubClient = getEventHubClientByName(eventHubName);
- final List partitionIds = Arrays.asList(eventHubClient.getRuntimeInformation().get().getPartitionIds());
- partitionIds.parallelStream()
- .forEach(partitionId -> result.addAll(getMessageFromPartition(eventHubClient, partitionId)));
- return result;
- }
-
- public List getMessageFromPartition(final EventHubClient eventHubClient, final String partitionId) {
- final List result = new ArrayList<>();
- try {
- final PartitionReceiver partitionReceiver = eventHubClient
- .createReceiver(EventHubClient.DEFAULT_CONSUMER_GROUP_NAME,
- partitionId, EventPosition.fromStartOfStream()).get();
- final Iterable data = partitionReceiver.receive(10).get();
- if (data != null) {
- data.forEach(eventData -> result.add(new String(eventData.getBytes())));
- }
- partitionReceiver.closeSync();
- } catch (Exception e) {
- // When exception, just return empty List
- e.printStackTrace();
- }
- return result;
- }
-
- public void close() throws Exception {
- for (final EventHubClient eventHubClient : eventHubClientMap.values()) {
- eventHubClient.closeSync();
- }
- executorService.shutdown();
- }
-
- private EventHubClient getEventHubClientByName(final String eventHubName) throws Exception {
- if (eventHubClientMap.containsKey(eventHubName)) {
- return eventHubClientMap.get(eventHubName);
- } else {
- final ConnectionStringBuilder connStr = new ConnectionStringBuilder()
- .setNamespaceName(eventHubNamespace.name())
- .setEventHubName(eventHubName)
- .setSasKeyName(SAS_KAY_NAME)
- .setSasKey(getEventHubKey());
- final EventHubClient eventHubClient = EventHubClient.createFromConnectionStringSync(connStr.toString(), executorService);
- eventHubClientMap.put(eventHubName, eventHubClient);
- return eventHubClient;
- }
- }
-
- private String getEventHubKey() {
- return eventHubNamespace.listAuthorizationRules().get(0).getKeys().primaryKey();
- }
-
- public String getEventHubConnectionString() {
- return eventHubNamespace.listAuthorizationRules().get(0).getKeys().primaryConnectionString();
- }
-}
diff --git a/azure-maven-plugin-lib/pom.xml b/azure-maven-plugin-lib/pom.xml
index e3f98bb180..7b02fa4829 100644
--- a/azure-maven-plugin-lib/pom.xml
+++ b/azure-maven-plugin-lib/pom.xml
@@ -7,7 +7,7 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
azure-maven-plugin-lib
@@ -159,11 +159,6 @@
lombok
provided
-
- com.microsoft.azure
- azure
- compile
-
com.github.java-json-tools
json-schema-validator
@@ -177,6 +172,15 @@
+
+
+ src/main/resources
+ true
+
+ schema/**/*.json
+
+
+
org.apache.maven.plugins
diff --git a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAppServiceMojo.java b/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAppServiceMojo.java
index f89b1244af..01e8f1cccf 100644
--- a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAppServiceMojo.java
+++ b/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAppServiceMojo.java
@@ -192,6 +192,7 @@ protected AzureAppService getOrCreateAzureAppServiceClient() {
com.microsoft.azure.toolkit.lib.Azure.az(AzureAccount.class).account().selectSubscription(Collections.singletonList(targetSubscriptionId));
appServiceClient = Azure.az(AzureAppService.class).subscription(targetSubscriptionId);
printCurrentSubscription(appServiceClient);
+ this.subscriptionId = targetSubscriptionId;
} catch (AzureLoginException | AzureExecutionException | IOException e) {
throw new AzureToolkitRuntimeException(String.format("Cannot authenticate due to error %s", e.getMessage()), e);
}
diff --git a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAzureMojo.java b/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAzureMojo.java
index 658f6041da..ea75e1fde2 100755
--- a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAzureMojo.java
+++ b/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/AbstractAzureMojo.java
@@ -34,6 +34,7 @@
import com.microsoft.azure.toolkit.lib.common.proxy.ProxyInfo;
import com.microsoft.azure.toolkit.lib.common.proxy.ProxyManager;
import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemeter;
+import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetryClient;
import com.microsoft.azure.toolkit.lib.common.utils.InstallationIdUtils;
import com.microsoft.azure.toolkit.lib.common.utils.TextUtils;
@@ -221,9 +222,6 @@ public abstract class AbstractAzureMojo extends AbstractMojo {
@JsonIgnore
private Account azureAccount;
- @JsonIgnore
- private com.microsoft.azure.management.Azure azure;
-
@Getter
@JsonIgnore
protected AzureTelemetryClient telemetryProxy;
@@ -440,16 +438,6 @@ protected void initTelemetryProxy() {
}
//endregion
- protected static void printCurrentSubscription(com.microsoft.azure.management.Azure azure) {
- if (azure == null) {
- return;
- }
- final com.microsoft.azure.management.resources.Subscription subscription = azure.getCurrentSubscription();
- if (subscription != null) {
- Log.info(String.format(SUBSCRIPTION_TEMPLATE, TextUtils.cyan(subscription.displayName()), TextUtils.cyan(subscription.subscriptionId())));
- }
- }
-
public Map getTelemetryProperties() {
final Map map = new HashMap<>();
map.put(INSTALLATION_ID_KEY, getInstallationId());
@@ -691,4 +679,8 @@ protected static void checkSubscription(List subscriptions, String
}
}
+ protected void updateTelemetryProperties() {
+ Optional.ofNullable(AzureTelemetry.getActionContext().getProperties()).ifPresent(properties ->
+ properties.forEach((key, value) -> telemetryProxy.addDefaultProperty(key, value)));
+ }
}
diff --git a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/auth/AzureClientFactory.java b/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/auth/AzureClientFactory.java
deleted file mode 100644
index 887ea469c5..0000000000
--- a/azure-maven-plugin-lib/src/main/java/com/microsoft/azure/maven/auth/AzureClientFactory.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.maven.auth;
-
-import com.microsoft.azure.management.Azure;
-import com.microsoft.azure.management.Azure.Authenticated;
-import com.microsoft.azure.toolkit.lib.auth.Account;
-import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
-import com.microsoft.azure.toolkit.lib.auth.exception.AzureLoginException;
-import org.apache.commons.lang3.StringUtils;
-
-import java.io.IOException;
-
-public class AzureClientFactory {
- public static Azure getAzureClient(String userAgent, String defaultSubscriptionId) throws IOException, AzureLoginException {
- final Account account = com.microsoft.azure.toolkit.lib.Azure.az(AzureAccount.class).account();
- final Authenticated authenticated = Azure.configure().withUserAgent(userAgent)
- .authenticate(account.getTokenCredentialV1(defaultSubscriptionId));
-
- return StringUtils.isEmpty(defaultSubscriptionId) ? authenticated.withDefaultSubscription() :
- authenticated.withSubscription(defaultSubscriptionId);
- }
-}
diff --git a/azure-maven-plugin-lib/src/main/resources/schema/maven/AzureAppServiceMavenPlugin.json b/azure-maven-plugin-lib/src/main/resources/schema/maven/AzureAppServiceMavenPlugin.json
new file mode 100644
index 0000000000..e9040f0886
--- /dev/null
+++ b/azure-maven-plugin-lib/src/main/resources/schema/maven/AzureAppServiceMavenPlugin.json
@@ -0,0 +1,148 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "Configuration",
+ "description": "Configuration for Maven plugin for Azure Web App",
+ "properties": {
+ "subscriptionId": {
+ "$ref": "classpath:///schema/common/UUID.json"
+ },
+ "resourceGroup": {
+ "$ref": "classpath:///schema/common/ResourceGroupName.json"
+ },
+ "appName": {
+ "$ref": "classpath:///schema/appservice/AppServiceName.json"
+ },
+ "appServicePlanName": {
+ "$ref": "classpath:///schema/appservice/AppServicePlanName.json"
+ },
+ "appServicePlanResourceGroup": {
+ "$ref": "classpath:///schema/common/ResourceGroupName.json"
+ },
+ "auth": {
+ "$ref": "#/definitions/auth"
+ },
+ "deploymentSlot": {
+ "$ref": "#/definitions/deployment-slot"
+ },
+ "appSettings": {
+ "type": "object"
+ },
+ "allowTelemetry": {
+ "type": "boolean",
+ "default": true
+ },
+ "failsOnError": {
+ "type": "boolean",
+ "default": true
+ },
+ "authType": {
+ "$ref": "classpath:///schema/common/AuthConfiguration.json#/definitions/auth-type",
+ "deprecationMessage": "Please set auth related properties like type in "
+ }
+ },
+ "required": [
+ "appName",
+ "resourceGroup"
+ ],
+ "definitions": {
+ "deployment-slot": {
+ "title": "DeploymentSlotConfiguration",
+ "description": "Deployment slot configuration for Maven plugin for Azure Web App",
+ "type": "object",
+ "properties": {
+ "name": {
+ "$ref": "classpath:///schema/appservice/DeploymentSlotName.json"
+ },
+ "configurationSource": {
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
+ }
+ },
+ "required": [
+ "name"
+ ]
+ },
+ "auth": {
+ "title": "AuthConfiguration",
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description": "The auth config for accessing azure resources",
+ "type": "object",
+ "properties": {
+ "type": {
+ "$ref": "classpath:///schema/common/AuthConfiguration.json#/definitions/auth-type"
+ },
+ "client": {
+ "$ref": "classpath:///schema/common/UUID.json"
+ },
+ "tenant": {
+ "$ref": "classpath:///schema/common/UUID.json"
+ },
+ "serverId": {
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
+ },
+ "key": {
+ "description": "Password",
+ "type": "string"
+ },
+ "certificate": {
+ "description": "The absolute path of your certificate",
+ "type": "string"
+ },
+ "certificatePassword": {
+ "description": "The password for your certificate, if there is any",
+ "type": "string"
+ },
+ "environment": {
+ "$ref": "classpath:///schema/common/AzureEnvironment.json"
+ }
+ },
+ "allOf": [
+ {
+ "if": {
+ "properties": {
+ "type": {
+ "pattern": "(?i)^service_principal$"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "then": {
+ "anyOf": [
+ {
+ "required": [
+ "client",
+ "tenant",
+ "key"
+ ]
+ },
+ {
+ "required": [
+ "client",
+ "tenant",
+ "certificate"
+ ]
+ },
+ {
+ "required": [
+ "serverId"
+ ]
+ }
+ ]
+ }
+ }
+ ],
+ "not": {
+ "required": [
+ "key",
+ "certificate"
+ ]
+ },
+ "dependencies": {
+ "certificatePassword": [
+ "certificate"
+ ]
+ }
+ }
+ }
+}
diff --git a/azure-sfmesh-maven-plugin/pom.xml b/azure-sfmesh-maven-plugin/pom.xml
index dc3bbf31dc..2c0aab652d 100644
--- a/azure-sfmesh-maven-plugin/pom.xml
+++ b/azure-sfmesh-maven-plugin/pom.xml
@@ -8,7 +8,7 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
azure-sfmesh-maven-plugin
diff --git a/azure-spring-cloud-maven-plugin/pom.xml b/azure-spring-cloud-maven-plugin/pom.xml
index 7ee6ebe140..c46a2221e0 100644
--- a/azure-spring-cloud-maven-plugin/pom.xml
+++ b/azure-spring-cloud-maven-plugin/pom.xml
@@ -12,7 +12,7 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
Azure Spring Cloud Maven Plugin
@@ -275,6 +275,56 @@
+
+
+
+ com.nickwongdev
+ aspectj-maven-plugin
+
+ false
+ 1.8
+ 1.8
+ ignore
+ 1.8
+ UTF-8
+ false
+ true
+ true
+
+
+
+ com.microsoft.azure
+ azure-toolkit-common-lib
+
+
+
+
+
+ compile-with-aspectj
+ process-classes
+
+
+ ${project.build.directory}/classes
+
+
+
+ compile
+
+
+
+ test-compile-with-aspectj
+ process-test-classes
+
+
+ ${project.build.directory}/test-classes
+
+
+
+ test-compile
+
+
+
+
diff --git a/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/core/pom.xml b/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/core/pom.xml
index bd07da9cb2..ca70e228b1 100644
--- a/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/core/pom.xml
+++ b/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/core/pom.xml
@@ -25,7 +25,7 @@
junit
junit
- 4.11
+ 4.13.1
test
diff --git a/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/service/pom.xml b/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/service/pom.xml
index b56e0f8b18..629561377c 100644
--- a/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/service/pom.xml
+++ b/azure-spring-cloud-maven-plugin/src/test/resources/maven/projects/parent-project/service/pom.xml
@@ -25,7 +25,7 @@
junit
junit
- 4.11
+ 4.13.1
test
diff --git a/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/pom.xml
index 69339e6f74..36df7025a3 100644
--- a/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
diff --git a/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/ApplicationInsights.java b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/ApplicationInsights.java
index b70ae743cb..ffd66b7c81 100644
--- a/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/ApplicationInsights.java
+++ b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/ApplicationInsights.java
@@ -1,3 +1,7 @@
+/*
+ * 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.toolkit.lib.applicationinsights;
import com.azure.core.http.policy.HttpLogDetailLevel;
@@ -5,10 +9,10 @@
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.management.exception.ManagementException;
import com.azure.core.management.profile.AzureProfile;
-import com.azure.resourcemanager.AzureResourceManager;
import com.azure.resourcemanager.applicationinsights.ApplicationInsightsManager;
import com.azure.resourcemanager.applicationinsights.models.ApplicationInsightsComponent;
import com.azure.resourcemanager.applicationinsights.models.ApplicationType;
+import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.azure.resourcemanager.resources.fluentcore.policy.ProviderRegistrationPolicy;
import com.azure.resourcemanager.resources.models.Providers;
@@ -94,7 +98,7 @@ public void delete(@Nonnull String subscriptionId, @Nonnull String resourceGroup
getApplicationInsightsManager(subscriptionId).components().deleteByResourceGroup(resourceGroup, name);
}
- @Cacheable(cacheName = "ApplicationInsightsManager", key = "$subscriptionId")
+ @Cacheable(cacheName = "applicationinsights/{}/manager", key = "$subscriptionId")
private ApplicationInsightsManager getApplicationInsightsManager(String subscriptionId) {
final Account account = Azure.az(AzureAccount.class).account();
final String tenantId = account.getSubscription(subscriptionId).getTenantId();
@@ -104,12 +108,14 @@ private ApplicationInsightsManager getApplicationInsightsManager(String subscrip
logOptions.setLogLevel(Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE));
final AzureProfile azureProfile = new AzureProfile(tenantId, subscriptionId, account.getEnvironment());
// todo: migrate resource provider related codes to common library
- final Providers providers = AzureResourceManager.configure()
+ final Providers providers = ResourceManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withPolicy(getUserAgentPolicy(userAgent))
.authenticate(account.getTokenCredential(subscriptionId), azureProfile)
.withSubscription(subscriptionId).providers();
return ApplicationInsightsManager
.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogOptions(logOptions)
.withPolicy(getUserAgentPolicy(userAgent))
.withPolicy(new ProviderRegistrationPolicy(providers)) // add policy to auto register resource providers
diff --git a/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/task/GetOrCreateApplicationInsightsTask.java b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/task/GetOrCreateApplicationInsightsTask.java
new file mode 100644
index 0000000000..022f3a1a0d
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-applicationinsights-lib/src/main/java/com/microsoft/azure/toolkit/lib/applicationinsights/task/GetOrCreateApplicationInsightsTask.java
@@ -0,0 +1,56 @@
+/*
+ * 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.toolkit.lib.applicationinsights.task;
+
+import com.azure.core.management.AzureEnvironment;
+import com.azure.core.management.exception.ManagementException;
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.applicationinsights.ApplicationInsights;
+import com.microsoft.azure.toolkit.lib.applicationinsights.ApplicationInsightsEntity;
+import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
+import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+
+import javax.annotation.Nonnull;
+
+import static com.microsoft.azure.toolkit.lib.auth.util.AzureEnvironmentUtils.getPortalUrl;
+
+public class GetOrCreateApplicationInsightsTask extends AzureTask {
+ private static final String APPLICATION_INSIGHTS_CREATE_START = "Creating application insights...";
+ private static final String APPLICATION_INSIGHTS_CREATED = "Successfully created the application insights %s " +
+ "for this Function App. You can visit %s/#@/resource%s/overview to view your " +
+ "Application Insights component.";
+
+ private final String subscriptionId;
+ private final String resourceGroup;
+ private final String name;
+ private final Region region;
+
+ public GetOrCreateApplicationInsightsTask(@Nonnull String subscriptionId, @Nonnull String resourceGroup, @Nonnull Region region, @Nonnull String name) {
+ this.subscriptionId = subscriptionId;
+ this.resourceGroup = resourceGroup;
+ this.name = name;
+ this.region = region;
+ }
+
+ @Override
+ public ApplicationInsightsEntity execute() {
+ final ApplicationInsights az = Azure.az(ApplicationInsights.class).subscription(subscriptionId);
+ try {
+ return az.get(resourceGroup, name);
+ } catch (ManagementException e) {
+ if (e.getResponse().getStatusCode() != 404) {
+ throw e;
+ }
+ }
+ AzureMessager.getMessager().info(APPLICATION_INSIGHTS_CREATE_START);
+ final AzureEnvironment environment = Azure.az(AzureAccount.class).account().getEnvironment();
+ final ApplicationInsightsEntity resource = Azure.az(ApplicationInsights.class).create(resourceGroup, region, name);
+ AzureMessager.getMessager().info(String.format(APPLICATION_INSIGHTS_CREATED, resource.getName(), getPortalUrl(environment), resource.getId()));
+ return resource;
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-appservice-lib/pom.xml
index 858b57c9f0..e493eba1f0 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
@@ -35,7 +35,12 @@
com.azure.resourcemanager
- azure-resourcemanager
+ azure-resourcemanager-appservice
+
+
+
+ com.microsoft.azure
+ azure-storage
@@ -78,17 +83,6 @@
commons-codec
commons-codec
-
- com.google.errorprone
- error_prone_core
- ${error.prone.core.version}
-
-
- com.google.guava
- guava
-
-
-
org.zeroturnaround
zt-zip
@@ -154,12 +148,11 @@
com.microsoft.azure
- azure
- compile
+ azure-toolkit-common-lib
com.microsoft.azure
- azure-toolkit-common-lib
+ azure-toolkit-applicationinsights-lib
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/AzureAppService.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/AzureAppService.java
index 05082f2587..6135169a54 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/AzureAppService.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/AzureAppService.java
@@ -7,7 +7,9 @@
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.management.profile.AzureProfile;
-import com.azure.resourcemanager.AzureResourceManager;
+import com.azure.resourcemanager.appservice.AppServiceManager;
+import com.azure.resourcemanager.appservice.fluent.models.ResourceNameAvailabilityInner;
+import com.azure.resourcemanager.appservice.models.CheckNameResourceTypes;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureConfiguration;
import com.microsoft.azure.toolkit.lib.AzureService;
@@ -31,6 +33,7 @@
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
import com.microsoft.azure.toolkit.lib.common.cache.Preload;
+import com.microsoft.azure.toolkit.lib.common.entity.CheckNameAvailabilityResultEntity;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import org.apache.commons.lang3.StringUtils;
@@ -51,20 +54,20 @@ private AzureAppService(@Nonnull final List subscriptions) {
super(AzureAppService::new, subscriptions);
}
- @Cacheable(cacheName = "appservcie/functionapp/{}", key = "$id")
+ @Cacheable(cacheName = "appservice/functionapp/{}", key = "$id")
@AzureOperation(name = "functionapp.get.id", params = {"id"}, type = AzureOperation.Type.SERVICE)
public IFunctionApp functionApp(String id) {
- return new FunctionApp(id, getAzureResourceManager(Utils.getSubscriptionId(id)));
+ return new FunctionApp(id, getAppServiceManager(Utils.getSubscriptionId(id)));
}
public IFunctionApp functionApp(String resourceGroup, String name) {
return functionApp(getDefaultSubscription().getId(), resourceGroup, name);
}
- @Cacheable(cacheName = "appservcie/{}/rg/{}/functionapp/{}", key = "$sid/$rg/$name")
+ @Cacheable(cacheName = "appservice/{}/rg/{}/functionapp/{}", key = "$sid/$rg/$name")
@AzureOperation(name = "functionapp.get.name|rg|sid", params = {"name", "rg", "sid"}, type = AzureOperation.Type.SERVICE)
public IFunctionApp functionApp(String sid, String rg, String name) {
- return new FunctionApp(sid, rg, name, getAzureResourceManager(sid));
+ return new FunctionApp(sid, rg, name, getAppServiceManager(sid));
}
public IFunctionApp functionApp(FunctionAppEntity entity) {
@@ -80,10 +83,10 @@ public List functionApps(boolean... force) {
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/{}/functionapps", key = "$sid", condition = "!(force&&force[0])")
+ @Cacheable(cacheName = "appservice/{}/functionapps", key = "$sid", condition = "!(force&&force[0])")
@AzureOperation(name = "functionapp.list.subscription", params = "sid", type = AzureOperation.Type.SERVICE)
private List functionApps(String sid, boolean... force) {
- final AzureResourceManager azureResourceManager = getAzureResourceManager(sid);
+ final AppServiceManager azureResourceManager = getAppServiceManager(sid);
return azureResourceManager
.functionApps().list().stream().parallel()
.filter(functionAppBasic -> StringUtils.containsIgnoreCase(functionAppBasic.innerModel().kind(), "functionapp")) // Filter out function apps
@@ -91,20 +94,20 @@ private List functionApps(String sid, boolean... force) {
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/webapp/{}", key = "$id")
+ @Cacheable(cacheName = "appservice/webapp/{}", key = "$id")
@AzureOperation(name = "webapp.get.id", params = "id", type = AzureOperation.Type.SERVICE)
public IWebApp webapp(String id) {
- return new WebApp(id, getAzureResourceManager(Utils.getSubscriptionId(id)));
+ return new WebApp(id, getAppServiceManager(Utils.getSubscriptionId(id)));
}
public IWebApp webapp(String resourceGroup, String name) {
return webapp(getDefaultSubscription().getId(), resourceGroup, name);
}
- @Cacheable(cacheName = "appservcie/{}/rg/{}/webapp/{}", key = "$sid/$rg/$name")
+ @Cacheable(cacheName = "appservice/{}/rg/{}/webapp/{}", key = "$sid/$rg/$name")
@AzureOperation(name = "webapp.get.name|rg|sid", params = {"name", "rg", "sid"}, type = AzureOperation.Type.SERVICE)
public IWebApp webapp(String sid, String rg, String name) {
- return new WebApp(sid, rg, name, getAzureResourceManager(sid));
+ return new WebApp(sid, rg, name, getAppServiceManager(sid));
}
public IWebApp webapp(WebAppEntity webAppEntity) {
@@ -120,38 +123,46 @@ public List webapps(boolean... force) {
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/{}/webapps", key = "$sid", condition = "!(force&&force[0])")
+ @AzureOperation(name = "appservice.check_name", params = "name", type = AzureOperation.Type.SERVICE)
+ public CheckNameAvailabilityResultEntity checkNameAvailability(String subscriptionId, String name) {
+ final AppServiceManager azureResourceManager = getAppServiceManager(subscriptionId);
+ final ResourceNameAvailabilityInner result = azureResourceManager.webApps().manager()
+ .serviceClient().getResourceProviders().checkNameAvailability(name, CheckNameResourceTypes.MICROSOFT_WEB_SITES);
+ return new CheckNameAvailabilityResultEntity(result.nameAvailable(), result.reason().toString(), result.message());
+ }
+
+ @Cacheable(cacheName = "appservice/{}/webapps", key = "$sid", condition = "!(force&&force[0])")
@AzureOperation(name = "webapp.list.subscription", params = "sid", type = AzureOperation.Type.SERVICE)
private List webapps(String sid, boolean... force) {
- final AzureResourceManager azureResourceManager = getAzureResourceManager(sid);
+ final AppServiceManager azureResourceManager = getAppServiceManager(sid);
return azureResourceManager.webApps().list().stream().parallel()
.filter(webAppBasic -> !StringUtils.containsIgnoreCase(webAppBasic.innerModel().kind(), "functionapp")) // Filter out function apps
.map(webAppBasic -> new WebApp(webAppBasic, azureResourceManager))
.collect(Collectors.toList());
}
- public @Nonnull
+ @Nonnull
@AzureOperation(name = "webapp|runtime.list.os|version", params = {"os.getValue()", "version.getValue()"}, type = AzureOperation.Type.SERVICE)
- List listWebAppRuntimes(@Nonnull OperatingSystem os, @Nonnull JavaVersion version) {
+ public List listWebAppRuntimes(@Nonnull OperatingSystem os, @Nonnull JavaVersion version) {
return Runtime.WEBAPP_RUNTIME.stream()
.filter(runtime -> Objects.equals(os, runtime.getOperatingSystem()) && Objects.equals(version, runtime.getJavaVersion()))
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/plan/{}", key = "$id")
+ @Cacheable(cacheName = "appservice/plan/{}", key = "$id")
@AzureOperation(name = "appservice|plan.get.id", params = "id", type = AzureOperation.Type.SERVICE)
public IAppServicePlan appServicePlan(String id) {
- return new AppServicePlan(id, getAzureResourceManager(Utils.getSubscriptionId(id)));
+ return new AppServicePlan(id, getAppServiceManager(Utils.getSubscriptionId(id)));
}
public IAppServicePlan appServicePlan(String resourceGroup, String name) {
return appServicePlan(getDefaultSubscription().getId(), resourceGroup, name);
}
- @Cacheable(cacheName = "appservcie/{}/rg/{}/plan/{}", key = "$sid/$rg/$name")
+ @Cacheable(cacheName = "appservice/{}/rg/{}/plan/{}", key = "$sid/$rg/$name")
@AzureOperation(name = "appservice|plan.get.name|rg|sid", params = {"name", "rg", "sid"}, type = AzureOperation.Type.SERVICE)
public IAppServicePlan appServicePlan(String sid, String rg, String name) {
- return new AppServicePlan(sid, rg, name, getAzureResourceManager(sid));
+ return new AppServicePlan(sid, rg, name, getAppServiceManager(sid));
}
public IAppServicePlan appServicePlan(AppServicePlanEntity entity) {
@@ -167,46 +178,46 @@ public List appServicePlans(boolean... force) {
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/{}/plans", key = "$sid", condition = "!(force&&force[0])")
+ @Cacheable(cacheName = "appservice/{}/plans", key = "$sid", condition = "!(force&&force[0])")
@AzureOperation(name = "appservice|plan.list.subscription", params = "sid", type = AzureOperation.Type.SERVICE)
public List appServicePlans(String sid, boolean... force) {
- final AzureResourceManager azureResourceManager = getAzureResourceManager(sid);
+ final AppServiceManager azureResourceManager = getAppServiceManager(sid);
return azureResourceManager.appServicePlans().list().stream().parallel()
.map(appServicePlan -> new AppServicePlan(appServicePlan, azureResourceManager))
.collect(Collectors.toList());
}
- @Cacheable(cacheName = "appservcie/rg/{}/plans", key = "$rg", condition = "!(force&&force[0])")
+ @Cacheable(cacheName = "appservice/rg/{}/plans", key = "$rg", condition = "!(force&&force[0])")
@AzureOperation(name = "appservice|plan.list.rg", params = "rg", type = AzureOperation.Type.SERVICE)
public List appServicePlansByResourceGroup(String rg, boolean... force) {
return getSubscriptions().stream().parallel()
- .map(subscription -> getAzureResourceManager(subscription.getId()))
+ .map(subscription -> getAppServiceManager(subscription.getId()))
.flatMap(azureResourceManager -> azureResourceManager.appServicePlans().listByResourceGroup(rg).stream()
.map(appServicePlan -> new AppServicePlan(appServicePlan, azureResourceManager)))
.collect(Collectors.toList());
}
@Deprecated
- @Cacheable(cacheName = "appservcie/slot/{}", key = "$id")
+ @Cacheable(cacheName = "appservice/slot/{}", key = "$id")
@AzureOperation(name = "appservice|deployment.get.id", params = "id", type = AzureOperation.Type.SERVICE)
public IWebAppDeploymentSlot deploymentSlot(String id) {
- return new WebAppDeploymentSlot(id, getAzureResourceManager(Utils.getSubscriptionId(id)));
+ return new WebAppDeploymentSlot(id, getAppServiceManager(Utils.getSubscriptionId(id)));
}
// todo: share codes with other library which leverage track2 mgmt sdk
@Cacheable(cacheName = "appservice/{}/manager", key = "$sid")
@AzureOperation(name = "appservice.get_client.subscription", params = "sid", type = AzureOperation.Type.SERVICE)
- public AzureResourceManager getAzureResourceManager(String sid) {
+ public AppServiceManager getAppServiceManager(String sid) {
final Account account = Azure.az(AzureAccount.class).account();
final AzureConfiguration config = Azure.az().config();
final String userAgent = config.getUserAgent();
final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
- final AzureProfile azureProfile = new AzureProfile(account.getEnvironment());
- return AzureResourceManager.configure()
+ final AzureProfile azureProfile = new AzureProfile(null, sid, account.getEnvironment());
+ return AppServiceManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogLevel(logLevel)
.withPolicy(getUserAgentPolicy(userAgent)) // set user agent with policy
- .authenticate(account.getTokenCredential(sid), azureProfile)
- .withSubscription(sid);
+ .authenticate(account.getTokenCredential(sid), azureProfile);
}
private HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
@@ -216,4 +227,8 @@ private HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
return httpPipelineNextPolicy.process();
};
}
+
+ public String name() {
+ return "Microsoft.Web/sites";
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServiceConfig.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServiceConfig.java
index 84b02d7244..6a677558b4 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServiceConfig.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServiceConfig.java
@@ -5,12 +5,17 @@
package com.microsoft.azure.toolkit.lib.appservice.config;
+import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
+import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
+import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
import com.microsoft.azure.toolkit.lib.common.model.Region;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+import javax.annotation.Nonnull;
import java.util.Map;
@Getter
@@ -46,7 +51,37 @@ public AppServicePlanConfig getServicePlanConfig() {
.servicePlanResourceGroup(servicePlanResourceGroup())
.servicePlanName(servicePlanName())
.region(region())
- .os(runtime() == null ? null : runtime().os())
+ .os(runtime().os())
.pricingTier(pricingTier());
}
+
+ public static AppServiceConfig buildDefaultWebAppConfig(String resourceGroup, String appName, String packaging, JavaVersion javaVersion) {
+ RuntimeConfig runtimeConfig = new RuntimeConfig().os(OperatingSystem.LINUX).webContainer(StringUtils.equalsIgnoreCase(packaging, "war") ?
+ WebContainer.TOMCAT_85 : (StringUtils.equalsIgnoreCase(packaging, "ear") ? WebContainer.JBOSS_7 : WebContainer.JAVA_SE))
+ .javaVersion(javaVersion);
+ AppServiceConfig appServiceConfig = buildDefaultAppServiceConfig(resourceGroup, appName);
+ appServiceConfig.runtime(runtimeConfig);
+ return appServiceConfig;
+ }
+
+ public static AppServiceConfig buildDefaultFunctionConfig(String resourceGroup, String appName, JavaVersion javaVersion) {
+ RuntimeConfig runtimeConfig = new RuntimeConfig().os(OperatingSystem.WINDOWS).webContainer(WebContainer.JAVA_OFF)
+ .javaVersion(javaVersion);
+ AppServiceConfig appServiceConfig = buildDefaultAppServiceConfig(resourceGroup, appName);
+ appServiceConfig.runtime(runtimeConfig);
+ appServiceConfig.pricingTier(PricingTier.CONSUMPTION);
+ return appServiceConfig;
+ }
+
+ @Nonnull
+ private static AppServiceConfig buildDefaultAppServiceConfig(String resourceGroup, String appName) {
+ AppServiceConfig appServiceConfig = new AppServiceConfig();
+ appServiceConfig.region(Region.US_CENTRAL);
+
+ appServiceConfig.resourceGroup(resourceGroup);
+ appServiceConfig.appName(appName);
+ appServiceConfig.servicePlanResourceGroup(resourceGroup);
+ appServiceConfig.servicePlanName(String.format("asp-%s", appName));
+ return appServiceConfig;
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServicePlanConfig.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServicePlanConfig.java
index d3e46fb807..6e22a9c013 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServicePlanConfig.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/AppServicePlanConfig.java
@@ -5,6 +5,7 @@
package com.microsoft.azure.toolkit.lib.appservice.config;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
import com.microsoft.azure.toolkit.lib.common.model.Region;
@@ -15,6 +16,7 @@
@Getter
@Setter
@Accessors(fluent = true)
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class AppServicePlanConfig {
private String subscriptionId;
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/FunctionAppConfig.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/FunctionAppConfig.java
new file mode 100644
index 0000000000..7490414180
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/config/FunctionAppConfig.java
@@ -0,0 +1,18 @@
+/*
+ * 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.toolkit.lib.appservice.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+@Getter
+@Setter
+@Accessors(fluent = true)
+public class FunctionAppConfig extends AppServiceConfig {
+ private String appInsightsInstance;
+ private String appInsightsKey;
+ private boolean disableAppInsights;
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/OperatingSystem.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/OperatingSystem.java
index c905e4a2d2..675b3bdcad 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/OperatingSystem.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/OperatingSystem.java
@@ -5,11 +5,10 @@
package com.microsoft.azure.toolkit.lib.appservice.model;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
-import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
@@ -17,6 +16,7 @@
@Getter
@NoArgsConstructor
@AllArgsConstructor
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public enum OperatingSystem {
WINDOWS("windows"),
LINUX("linux"),
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/PricingTier.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/PricingTier.java
index 5fcff7c3f3..085ee2b10d 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/PricingTier.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/PricingTier.java
@@ -5,6 +5,7 @@
package com.microsoft.azure.toolkit.lib.appservice.model;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.google.common.collect.Sets;
import com.microsoft.azure.toolkit.lib.common.model.ExpandableParameter;
import lombok.AllArgsConstructor;
@@ -24,6 +25,7 @@
@Setter
@NoArgsConstructor
@AllArgsConstructor
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class PricingTier implements ExpandableParameter {
public static final PricingTier BASIC_B1 = new PricingTier("Basic", "B1");
public static final PricingTier BASIC_B2 = new PricingTier("Basic", "B2");
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/Runtime.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/Runtime.java
index 029a253e27..4e6086003f 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/Runtime.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/Runtime.java
@@ -45,7 +45,6 @@ public class Runtime {
public static final Runtime LINUX_JAVA8_TOMCAT85 = new Runtime(OperatingSystem.LINUX, WebContainer.TOMCAT_85, JavaVersion.JAVA_8);
public static final Runtime LINUX_JAVA8_JBOSS7 = new Runtime(OperatingSystem.LINUX, WebContainer.JBOSS_7, JavaVersion.JAVA_8);
public static final Runtime LINUX_JAVA11_JBOSS7 = new Runtime(OperatingSystem.LINUX, WebContainer.JBOSS_7, JavaVersion.JAVA_11);
- public static final Runtime LINUX_JAVA8_JBOSS72 = new Runtime(OperatingSystem.LINUX, WebContainer.JBOSS_72, JavaVersion.JAVA_8);
public static final Runtime LINUX_JAVA11_TOMCAT9 = new Runtime(OperatingSystem.LINUX, WebContainer.TOMCAT_9, JavaVersion.JAVA_11);
public static final Runtime LINUX_JAVA11_TOMCAT85 = new Runtime(OperatingSystem.LINUX, WebContainer.TOMCAT_85, JavaVersion.JAVA_11);
// Function
@@ -58,7 +57,7 @@ public class Runtime {
public static final List WEBAPP_RUNTIME = Collections.unmodifiableList(Arrays.asList(WINDOWS_JAVA8, WINDOWS_JAVA11, WINDOWS_JAVA8_TOMCAT9,
WINDOWS_JAVA8_TOMCAT85, WINDOWS_JAVA11_TOMCAT9, WINDOWS_JAVA11_TOMCAT85, LINUX_JAVA8, LINUX_JAVA11, LINUX_JAVA8_TOMCAT9, LINUX_JAVA8_TOMCAT85,
- LINUX_JAVA8_JBOSS72, LINUX_JAVA11_JBOSS7, LINUX_JAVA8_JBOSS7, LINUX_JAVA11_TOMCAT9, LINUX_JAVA11_TOMCAT85));
+ LINUX_JAVA11_JBOSS7, LINUX_JAVA8_JBOSS7, LINUX_JAVA11_TOMCAT9, LINUX_JAVA11_TOMCAT85));
public static final List FUNCTION_APP_RUNTIME = Collections.unmodifiableList(Arrays.asList(FUNCTION_LINUX_JAVA8, FUNCTION_LINUX_JAVA11,
FUNCTION_WINDOWS_JAVA8, FUNCTION_WINDOWS_JAVA11));
private static final List values =
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/WebContainer.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/WebContainer.java
index fa64371ad1..b4352ea250 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/WebContainer.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/model/WebContainer.java
@@ -35,7 +35,6 @@ public class WebContainer implements ExpandableParameter {
public static final WebContainer TOMCAT_85 = new WebContainer("tomcat 8.5");
public static final WebContainer TOMCAT_9 = new WebContainer("tomcat 9.0");
public static final WebContainer JBOSS_7 = new WebContainer("JBOSSEAP 7");
- public static final WebContainer JBOSS_72 = new WebContainer("JBOSSEAP 7.2");
public static final WebContainer TOMCAT_7_0_50 = new WebContainer("tomcat 7.0.50");
public static final WebContainer TOMCAT_7_0_62 = new WebContainer("tomcat 7.0.62");
@@ -56,7 +55,7 @@ public class WebContainer implements ExpandableParameter {
private static final Set values = Collections.unmodifiableSet(Sets.newHashSet(TOMCAT_7, TOMCAT_7_0_50, TOMCAT_7_0_62, TOMCAT_8,
TOMCAT_8_0_23, TOMCAT_85, TOMCAT_8_5_6, TOMCAT_8_5_20, TOMCAT_8_5_31, TOMCAT_8_5_34, TOMCAT_8_5_37, TOMCAT_9, TOMCAT_9_0_0, TOMCAT_9_0_8,
- TOMCAT_9_0_12, TOMCAT_9_0_14, JETTY_9_1_NEWEST, JETTY_9_1_V20131115, JETTY_9_3_NEWEST, JETTY_9_3_V20161014, JAVA_SE, JBOSS_72, JBOSS_7));
+ TOMCAT_9_0_12, TOMCAT_9_0_14, JETTY_9_1_NEWEST, JETTY_9_1_V20131115, JETTY_9_3_NEWEST, JETTY_9_3_V20161014, JAVA_SE, JBOSS_7));
private String value;
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/service/impl/AppServicePlan.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/service/impl/AppServicePlan.java
index e4c857cbab..8cd0b2b861 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/service/impl/AppServicePlan.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/service/impl/AppServicePlan.java
@@ -4,7 +4,7 @@
*/
package com.microsoft.azure.toolkit.lib.appservice.service.impl;
-import com.azure.resourcemanager.AzureResourceManager;
+import com.azure.resourcemanager.appservice.AppServiceManager;
import com.microsoft.azure.toolkit.lib.appservice.entity.AppServicePlanEntity;
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
@@ -23,21 +23,21 @@ public class AppServicePlan extends AbstractAzureManager implements IFunctionApp {
public static final JavaVersion DEFAULT_JAVA_VERSION = JavaVersion.JAVA_8;
private static final String UNSUPPORTED_OPERATING_SYSTEM = "Unsupported operating system %s";
- private final AzureResourceManager azureClient;
+ private final AppServiceManager azureClient;
- public FunctionApp(@Nonnull final String id, @Nonnull final AzureResourceManager azureClient) {
+ public FunctionApp(@Nonnull final String id, @Nonnull final AppServiceManager azureClient) {
super(id);
this.azureClient = azureClient;
}
public FunctionApp(@Nonnull final String subscriptionId, @Nonnull final String resourceGroup, @Nonnull final String name,
- @Nonnull final AzureResourceManager azureClient) {
+ @Nonnull final AppServiceManager azureClient) {
super(subscriptionId, resourceGroup, name);
this.azureClient = azureClient;
}
- public FunctionApp(@Nonnull WebSiteBase webSiteBase, @Nonnull final AzureResourceManager azureClient) {
+ public FunctionApp(@Nonnull WebSiteBase webSiteBase, @Nonnull final AppServiceManager azureClient) {
super(webSiteBase);
this.azureClient = azureClient;
}
@@ -137,7 +136,7 @@ public AbstractAppService
@AzureOperation(name = "appservice|plan.create_update", params = {"this.config.servicePlanName()"}, type = AzureOperation.Type.SERVICE)
public IAppServicePlan execute() {
+ SchemaValidator.getInstance().validateAndThrow("appservice/AppServicePlan", config);
final AzureAppService az = Azure.az(AzureAppService.class).subscription(config.subscriptionId());
final IAppServicePlan appServicePlan = az.appServicePlan(config.servicePlanResourceGroup(), config.servicePlanName());
final String servicePlanName = config.servicePlanName();
if (!appServicePlan.exists()) {
+ SchemaValidator.getInstance().validateAndThrow("appservice/CreateAppServicePlan", config);
AzureMessager.getMessager().info(String.format(CREATE_APP_SERVICE_PLAN, servicePlanName));
AzureTelemetry.getActionContext().setProperty(CREATE_NEW_APP_SERVICE_PLAN, String.valueOf(true));
- if (config.os() == null) {
- throw new AzureToolkitRuntimeException("Missing required configuration for 'runtime.os'.");
- }
-
- if (config.region() == null) {
- throw new AzureToolkitRuntimeException("Missing required configuration for 'region'.");
- }
-
- if (config.pricingTier() == null) {
- throw new AzureToolkitRuntimeException("Missing required configuration for 'pricingTier'.");
- }
-
+ new CreateResourceGroupTask(this.config.subscriptionId(), config.servicePlanResourceGroup(), config.region()).execute();
appServicePlan.create()
.withName(servicePlanName)
.withResourceGroup(config.servicePlanResourceGroup())
@@ -59,7 +51,7 @@ public IAppServicePlan execute() {
AzureMessager.getMessager().warning(String.format("Skip region update for existing service plan '%s' since it is not allowed.",
appServicePlan.name()));
}
- if (config.pricingTier() != null) {
+ if (config.pricingTier() != null && !Objects.equals(config.pricingTier(), appServicePlan.entity().getPricingTier())) {
// apply pricing tier to service plan
appServicePlan.update().withPricingTier(config.pricingTier()).commit();
}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateFunctionAppTask.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateFunctionAppTask.java
new file mode 100644
index 0000000000..f630f52cce
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateFunctionAppTask.java
@@ -0,0 +1,269 @@
+/*
+ * 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.toolkit.lib.appservice.task;
+
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.applicationinsights.ApplicationInsightsEntity;
+import com.microsoft.azure.toolkit.lib.applicationinsights.task.GetOrCreateApplicationInsightsTask;
+import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
+import com.microsoft.azure.toolkit.lib.appservice.config.FunctionAppConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig;
+import com.microsoft.azure.toolkit.lib.appservice.model.DockerConfiguration;
+import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
+import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
+import com.microsoft.azure.toolkit.lib.appservice.model.Runtime;
+import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppServiceUpdater;
+import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionApp;
+import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionAppBase;
+import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionAppDeploymentSlot;
+import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
+import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
+import com.microsoft.azure.toolkit.lib.common.model.ResourceGroup;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
+import com.microsoft.azure.toolkit.lib.resource.task.CreateResourceGroupTask;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+public class CreateOrUpdateFunctionAppTask extends AzureTask> {
+ public static final String APPINSIGHTS_INSTRUMENTATION_KEY = "APPINSIGHTS_INSTRUMENTATIONKEY";
+ private static final String APPLICATION_INSIGHTS_CREATE_FAILED = "Unable to create the Application Insights " +
+ "for the Function App due to error %s. Please use the Azure Portal to manually create and configure the " +
+ "Application Insights if needed.";
+ private static final String CREATE_FUNCTION_APP = "Creating function app %s...";
+ private static final String CREATE_FUNCTION_APP_DONE = "Successfully created function app %s.";
+ private static final String CREATE_NEW_FUNCTION_APP = "isCreateNewFunctionApp";
+ private static final String UPDATE_FUNCTION_APP = "Updating target Function App %s...";
+ private static final String UPDATE_FUNCTION_DONE = "Successfully updated Function App %s.";
+ private static final String FUNCTIONS_WORKER_RUNTIME_NAME = "FUNCTIONS_WORKER_RUNTIME";
+ private static final String FUNCTIONS_WORKER_RUNTIME_VALUE = "java";
+ private static final String SET_FUNCTIONS_WORKER_RUNTIME = "Set function worker runtime to java.";
+ private static final String CUSTOMIZED_FUNCTIONS_WORKER_RUNTIME_WARNING = "App setting `FUNCTIONS_WORKER_RUNTIME` doesn't " +
+ "meet the requirement of Azure Java Functions, the value should be `java`.";
+ private static final String FUNCTIONS_EXTENSION_VERSION_NAME = "FUNCTIONS_EXTENSION_VERSION";
+ private static final String FUNCTIONS_EXTENSION_VERSION_VALUE = "~3";
+ private static final String SET_FUNCTIONS_EXTENSION_VERSION = "Functions extension version " +
+ "isn't configured, setting up the default value.";
+ private static final String FUNCTION_APP_NOT_EXIST_FOR_SLOT = "The Function App specified in pom.xml does not exist. " +
+ "Please make sure the Web App name is correct.";
+ private static final String FUNCTION_SLOT_CREATE_START = "The specified function slot does not exist. " +
+ "Creating a new slot...";
+ private static final String FUNCTION_SLOT_CREATED = "Successfully created the function slot: %s.";
+ private static final String FUNCTION_SLOT_UPDATE = "Updating the specified function slot...";
+ private static final String FUNCTION_SLOT_UPDATE_DONE = "Successfully updated the function slot: %s.";
+
+ public static final JavaVersion DEFAULT_FUNCTION_JAVA_VERSION = JavaVersion.JAVA_8;
+
+ private final FunctionAppConfig functionAppConfig;
+ private final List> tasks = new ArrayList<>();
+
+ private ResourceGroup resourceGroup;
+ private IAppServicePlan appServicePlan;
+ private ApplicationInsightsEntity applicationInsights;
+ private IFunctionAppBase> functionApp;
+
+
+ public CreateOrUpdateFunctionAppTask(@Nonnull final FunctionAppConfig config) {
+ this.functionAppConfig = config;
+ initTasks();
+ }
+
+ private void initTasks() {
+ final IFunctionApp functionApp = Azure.az(AzureAppService.class).subscription(functionAppConfig.subscriptionId())
+ .functionApp(functionAppConfig.resourceGroup(), functionAppConfig.appName());
+ registerSubTask(getResourceGroupTask(), result -> this.resourceGroup = result);
+ registerSubTask(getServicePlanTask(), result -> this.appServicePlan = result);
+ // get/create ai instances only if user didn't specify ai connection string in app settings
+ if (!functionAppConfig.disableAppInsights() && !functionAppConfig.appSettings().containsKey(APPINSIGHTS_INSTRUMENTATION_KEY)) {
+ if (StringUtils.isNotEmpty(functionAppConfig.appInsightsKey())) {
+ this.applicationInsights = ApplicationInsightsEntity.builder().instrumentationKey(functionAppConfig.appInsightsKey()).build();
+ } else if (StringUtils.isNotEmpty(functionAppConfig.appInsightsInstance()) || !functionApp.exists()) {
+ // create ai instance by default when create new function
+ registerSubTask(getApplicationInsightsTask(), result -> this.applicationInsights = result);
+ }
+ }
+ if (StringUtils.isEmpty(functionAppConfig.deploymentSlotName())) {
+ final AzureTask functionTask = functionApp.exists() ?
+ getUpdateFunctionAppTask(functionApp) : getCreateFunctionAppTask(functionApp);
+ registerSubTask(functionTask, result -> this.functionApp = result);
+ } else {
+ final IFunctionAppDeploymentSlot deploymentSlot = getFunctionDeploymentSlot(functionApp);
+ final AzureTask slotTask = deploymentSlot.exists() ?
+ getUpdateFunctionSlotTask(deploymentSlot) : getCreateFunctionSlotTask(deploymentSlot);
+ registerSubTask(slotTask, result -> this.functionApp = result);
+ }
+ }
+
+ private void registerSubTask(AzureTask task, Consumer consumer) {
+ tasks.add(new AzureTask<>(() -> {
+ T result = task.getSupplier().get();
+ consumer.accept(result);
+ return result;
+ }));
+ }
+
+ private AzureTask getCreateFunctionAppTask(final IFunctionApp functionApp) {
+ final AzureString title = AzureString.format("Create new app({0}) on subscription({1})",
+ functionAppConfig.appName(), functionAppConfig.subscriptionId());
+ return new AzureTask<>(title, () -> {
+ AzureTelemetry.getActionContext().setProperty(CREATE_NEW_FUNCTION_APP, String.valueOf(true));
+ AzureMessager.getMessager().info(String.format(CREATE_FUNCTION_APP, functionAppConfig.appName()));
+ final Map appSettings = processAppSettingsWithDefaultValue();
+ Optional.ofNullable(applicationInsights).ifPresent(insights ->
+ appSettings.put(APPINSIGHTS_INSTRUMENTATION_KEY, applicationInsights.getInstrumentationKey()));
+ final IFunctionApp result = functionApp.create().withName(functionAppConfig.appName())
+ .withResourceGroup(resourceGroup.getName())
+ .withPlan(appServicePlan.id())
+ .withRuntime(getRuntime(functionAppConfig.runtime()))
+ .withDockerConfiguration(getDockerConfiguration(functionAppConfig.runtime()))
+ .withAppSettings(appSettings)
+ .commit();
+ AzureMessager.getMessager().info(String.format(CREATE_FUNCTION_APP_DONE, result.name()));
+ return result;
+ });
+ }
+
+ private Map processAppSettingsWithDefaultValue() {
+ final Map appSettings = functionAppConfig.appSettings();
+ setDefaultAppSetting(appSettings, FUNCTIONS_WORKER_RUNTIME_NAME, SET_FUNCTIONS_WORKER_RUNTIME,
+ FUNCTIONS_WORKER_RUNTIME_VALUE, CUSTOMIZED_FUNCTIONS_WORKER_RUNTIME_WARNING);
+ setDefaultAppSetting(appSettings, FUNCTIONS_EXTENSION_VERSION_NAME, SET_FUNCTIONS_EXTENSION_VERSION,
+ FUNCTIONS_EXTENSION_VERSION_VALUE, null);
+ return appSettings;
+ }
+
+ private void setDefaultAppSetting(Map result, String settingName, String settingIsEmptyMessage,
+ String defaultValue, String warningMessage) {
+ final String setting = result.get(settingName);
+ if (StringUtils.isEmpty(setting)) {
+ AzureMessager.getMessager().info(settingIsEmptyMessage);
+ result.put(settingName, defaultValue);
+ return;
+ }
+ // Show warning message when user set a different value
+ if (!StringUtils.equalsIgnoreCase(setting, defaultValue) && StringUtils.isNotEmpty(warningMessage)) {
+ AzureMessager.getMessager().warning(warningMessage);
+ }
+ }
+
+ private AzureTask getUpdateFunctionAppTask(final IFunctionApp functionApp) {
+ final AzureString title = AzureString.format("Update function app({0})", functionAppConfig.appName());
+ return new AzureTask<>(title, () -> {
+ AzureMessager.getMessager().info(String.format(UPDATE_FUNCTION_APP, functionApp.name()));
+ // update app settings
+ final IAppServiceUpdater extends IFunctionApp> update = functionApp.update();
+ final Map appSettings = processAppSettingsWithDefaultValue();
+ if (functionAppConfig.disableAppInsights()) {
+ update.withoutAppSettings(APPINSIGHTS_INSTRUMENTATION_KEY);
+ } else if (applicationInsights != null) {
+ appSettings.put(APPINSIGHTS_INSTRUMENTATION_KEY, applicationInsights.getInstrumentationKey());
+ }
+ final IFunctionApp result = update.withPlan(appServicePlan.id())
+ .withRuntime(getRuntime(functionAppConfig.runtime()))
+ .withDockerConfiguration(getDockerConfiguration(functionAppConfig.runtime()))
+ .withAppSettings(appSettings)
+ .commit();
+ AzureMessager.getMessager().info(String.format(UPDATE_FUNCTION_DONE, functionApp.name()));
+ return result;
+ });
+ }
+
+ private AzureTask getCreateFunctionSlotTask(IFunctionAppDeploymentSlot deploymentSlot) {
+ final AzureString title = AzureString.format("Create new slot({0}) on function app ({1})",
+ functionAppConfig.deploymentSlotName(), functionAppConfig.appName());
+ return new AzureTask<>(title, () -> {
+ AzureMessager.getMessager().info(FUNCTION_SLOT_CREATE_START);
+ final Map appSettings = processAppSettingsWithDefaultValue();
+ Optional.ofNullable(applicationInsights).ifPresent(insights ->
+ appSettings.put(APPINSIGHTS_INSTRUMENTATION_KEY, applicationInsights.getInstrumentationKey()));
+ final IFunctionAppDeploymentSlot result = deploymentSlot.create().withAppSettings(appSettings)
+ .withConfigurationSource(functionAppConfig.deploymentSlotConfigurationSource())
+ .withName(functionAppConfig.deploymentSlotName()).commit();
+ AzureMessager.getMessager().info(String.format(FUNCTION_SLOT_CREATED, result.name()));
+ return result;
+ });
+ }
+
+ private AzureTask getUpdateFunctionSlotTask(IFunctionAppDeploymentSlot deploymentSlot) {
+ final AzureString title = AzureString.format("Update function deployment slot({0})", functionAppConfig.deploymentSlotName());
+ return new AzureTask<>(title, () -> {
+ AzureMessager.getMessager().info(FUNCTION_SLOT_UPDATE);
+ final Map appSettings = processAppSettingsWithDefaultValue();
+ final IFunctionAppDeploymentSlot.Updater update = deploymentSlot.update();
+ if (functionAppConfig.disableAppInsights()) {
+ update.withoutAppSettings(APPINSIGHTS_INSTRUMENTATION_KEY);
+ } else if (applicationInsights != null) {
+ appSettings.put(APPINSIGHTS_INSTRUMENTATION_KEY, applicationInsights.getInstrumentationKey());
+ }
+ final IFunctionAppDeploymentSlot result = update.withAppSettings(appSettings).commit();
+ AzureMessager.getMessager().info(String.format(FUNCTION_SLOT_UPDATE_DONE, result.name()));
+ return deploymentSlot;
+ });
+ }
+
+ private IFunctionAppDeploymentSlot getFunctionDeploymentSlot(final IFunctionApp functionApp) {
+ if (!functionApp.exists()) {
+ throw new AzureToolkitRuntimeException(FUNCTION_APP_NOT_EXIST_FOR_SLOT);
+ }
+ return functionApp.deploymentSlot(functionAppConfig.deploymentSlotName());
+ }
+
+ private AzureTask getApplicationInsightsTask() {
+ return new AzureTask<>(() -> {
+ try {
+ final String name = StringUtils.firstNonEmpty(functionAppConfig.appInsightsInstance(), functionAppConfig.appName());
+ return new GetOrCreateApplicationInsightsTask(functionAppConfig.subscriptionId(),
+ functionAppConfig.resourceGroup(), functionAppConfig.region(), name).getSupplier().get();
+ } catch (final Exception e) {
+ AzureMessager.getMessager().warning(String.format(APPLICATION_INSIGHTS_CREATE_FAILED, e.getMessage()));
+ return null;
+ }
+ });
+ }
+
+ private CreateResourceGroupTask getResourceGroupTask() {
+ return new CreateResourceGroupTask(functionAppConfig.subscriptionId(), functionAppConfig.resourceGroup(), functionAppConfig.region());
+ }
+
+ private CreateOrUpdateAppServicePlanTask getServicePlanTask() {
+ return new CreateOrUpdateAppServicePlanTask(functionAppConfig.getServicePlanConfig());
+ }
+
+ private Runtime getRuntime(RuntimeConfig runtime) {
+ return Runtime.getRuntime(runtime.os(),
+ WebContainer.JAVA_OFF,
+ OperatingSystem.DOCKER != runtime.os() ? runtime.javaVersion() : JavaVersion.OFF);
+ }
+
+ // todo: remove duplicated with Create Web App Task
+ private DockerConfiguration getDockerConfiguration(RuntimeConfig runtime) {
+ if (OperatingSystem.DOCKER == runtime.os()) {
+ return DockerConfiguration.builder()
+ .userName(runtime.username())
+ .password(runtime.password())
+ .registryUrl(runtime.registryUrl())
+ .image(runtime.image())
+ .startUpCommand(runtime.startUpCommand())
+ .build();
+ }
+ return null;
+ }
+
+ @Override
+ public IFunctionAppBase> execute() {
+ this.tasks.forEach(t -> t.getSupplier().get());
+ return functionApp;
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateWebAppTask.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateWebAppTask.java
index dcbbe97d3f..5d986a8537 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateWebAppTask.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/CreateOrUpdateWebAppTask.java
@@ -16,14 +16,19 @@
import com.microsoft.azure.toolkit.lib.appservice.model.Runtime;
import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppServiceUpdater;
import com.microsoft.azure.toolkit.lib.appservice.service.IWebApp;
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
+import com.microsoft.azure.toolkit.lib.common.entity.CheckNameAvailabilityResultEntity;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation.Type;
import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
import com.microsoft.azure.toolkit.lib.resource.task.CreateResourceGroupTask;
+import lombok.Setter;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import reactor.core.publisher.Flux;
@@ -32,6 +37,8 @@
import java.util.HashMap;
import java.util.List;
+import static com.microsoft.azure.toolkit.lib.appservice.utils.Utils.throwForbidCreateResourceWarning;
+
public class CreateOrUpdateWebAppTask extends AzureTask {
private static final String CREATE_NEW_WEB_APP = "createNewWebApp";
@@ -43,6 +50,9 @@ public class CreateOrUpdateWebAppTask extends AzureTask {
private final AppServiceConfig config;
private final List> subTasks;
+ @Setter
+ private boolean skipCreateAzureResource;
+
public CreateOrUpdateWebAppTask(AppServiceConfig config) {
this.config = config;
this.subTasks = this.initTasks();
@@ -50,17 +60,21 @@ public CreateOrUpdateWebAppTask(AppServiceConfig config) {
private List> initTasks() {
final List> tasks = new ArrayList<>();
- tasks.add(new CreateResourceGroupTask(this.config.subscriptionId(), this.config.resourceGroup(), this.config.region()));
- if (StringUtils.isNotBlank(this.config.servicePlanResourceGroup())
- && !StringUtils.equalsIgnoreCase(this.config.servicePlanResourceGroup(), this.config.resourceGroup())) {
- tasks.add(new CreateResourceGroupTask(this.config.subscriptionId(), this.config.servicePlanResourceGroup(), this.config.region()));
- }
final AzureString title = AzureString.format("Create new web app({0})", this.config.appName());
-
+ AzureAppService az = Azure.az(AzureAppService.class);
tasks.add(new AzureTask<>(title, () -> {
- final IWebApp target = Azure.az(AzureAppService.class).subscription(config.subscriptionId())
+ final IWebApp target = az.subscription(config.subscriptionId())
.webapp(config.resourceGroup(), config.appName());
if (!target.exists()) {
+ if (skipCreateAzureResource) {
+ throwForbidCreateResourceWarning("Web app", config.appName());
+ }
+ CheckNameAvailabilityResultEntity result = az.checkNameAvailability(config.subscriptionId(), config.appName());
+ if (!result.isAvailable()) {
+ throw new AzureToolkitRuntimeException(AzureString.format("Cannot create webapp {0} due to error: {1}",
+ config.appName(),
+ result.getUnavailabilityReason()).getString());
+ }
return create();
}
return update(target);
@@ -72,17 +86,14 @@ private List> initTasks() {
private IWebApp create() {
AzureTelemetry.getActionContext().setProperty(CREATE_NEW_WEB_APP, String.valueOf(true));
AzureMessager.getMessager().info(String.format(CREATE_WEBAPP, config.appName()));
+
+ final Region region = this.config.region();
+ new CreateResourceGroupTask(this.config.subscriptionId(), this.config.resourceGroup(), region).execute();
final AzureAppService az = Azure.az(AzureAppService.class).subscription(config.subscriptionId());
final IWebApp webapp = az.webapp(config.resourceGroup(), config.appName());
final AppServicePlanConfig servicePlanConfig = config.getServicePlanConfig();
- // initialize default value for service plan creation
- if (StringUtils.isBlank(servicePlanConfig.servicePlanResourceGroup())) {
- servicePlanConfig.servicePlanResourceGroup(config.resourceGroup());
- }
- if (StringUtils.isBlank(servicePlanConfig.servicePlanName())) {
- servicePlanConfig.servicePlanName(String.format("asp-%s", config.appName()));
- }
final IAppServicePlan appServicePlan = new CreateOrUpdateAppServicePlanTask(servicePlanConfig).execute();
+
final IWebApp result = webapp.create().withName(config.appName())
.withResourceGroup(config.resourceGroup())
.withPlan(appServicePlan.id())
@@ -93,34 +104,28 @@ private IWebApp create() {
AzureMessager.getMessager().info(String.format(CREATE_WEB_APP_DONE, result.name()));
return result;
}
+
@AzureOperation(name = "webapp.update", params = {"this.config.appName()"}, type = Type.SERVICE)
private IWebApp update(final IWebApp webApp) {
AzureMessager.getMessager().info(String.format(UPDATE_WEBAPP, webApp.name()));
final IAppServicePlan currentPlan = webApp.plan();
final AppServicePlanConfig servicePlanConfig = config.getServicePlanConfig();
- if (StringUtils.isAllBlank(servicePlanConfig.servicePlanResourceGroup(), servicePlanConfig.servicePlanName())) {
- // initialize service plan creation from exising webapp if user doesn't specify it in config
- servicePlanConfig.servicePlanResourceGroup(currentPlan.resourceGroup());
- servicePlanConfig.servicePlanName(currentPlan.name());
- } else if (StringUtils.isAnyBlank(servicePlanConfig.servicePlanResourceGroup(), servicePlanConfig.servicePlanName())) {
- if (StringUtils.isBlank(servicePlanConfig.servicePlanResourceGroup())) {
- if (StringUtils.equalsIgnoreCase(servicePlanConfig.servicePlanName(), currentPlan.name())) {
- servicePlanConfig.servicePlanResourceGroup(currentPlan.resourceGroup());
- } else {
- servicePlanConfig.servicePlanResourceGroup(config.resourceGroup());
- }
- } else if (StringUtils.isBlank(servicePlanConfig.servicePlanName())) {
- if (StringUtils.equalsIgnoreCase(servicePlanConfig.servicePlanResourceGroup(), currentPlan.resourceGroup())) {
- servicePlanConfig.servicePlanName(currentPlan.name());
- } else {
- servicePlanConfig.servicePlanName(String.format("asp-%s", config.appName()));
- }
- }
+ if (skipCreateAzureResource && !Azure.az(AzureAppService.class).appServicePlan(servicePlanConfig.servicePlanResourceGroup(), servicePlanConfig.servicePlanName()).exists()) {
+ throwForbidCreateResourceWarning("Service plan", servicePlanConfig.servicePlanResourceGroup() + "/" + servicePlanConfig.servicePlanName());
}
+
+ final Runtime runtime = getRuntime(config.runtime());
final IAppServicePlan appServicePlan = new CreateOrUpdateAppServicePlanTask(servicePlanConfig).execute();
- final IWebApp result = webApp.update().withPlan(appServicePlan.id())
- .withRuntime(getRuntime(config.runtime()))
+ final IAppServiceUpdater extends IWebApp> draft = webApp.update();
+ if (!(StringUtils.equalsIgnoreCase(config.servicePlanResourceGroup(), currentPlan.resourceGroup()) &&
+ StringUtils.equalsIgnoreCase(config.servicePlanName(), currentPlan.name()))) {
+ draft.withPlan(appServicePlan.id());
+ }
+ if (!webApp.getRuntime().equals(runtime)) {
+ draft.withRuntime(runtime);
+ }
+ final IWebApp result = draft
.withDockerConfiguration(getDockerConfiguration(config.runtime()))
.withAppSettings(ObjectUtils.firstNonNull(config.appSettings(), new HashMap<>()))
.commit();
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployFunctionAppTask.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployFunctionAppTask.java
new file mode 100644
index 0000000000..2375015aed
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployFunctionAppTask.java
@@ -0,0 +1,174 @@
+/*
+ * 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.toolkit.lib.appservice.task;
+
+import com.azure.core.management.exception.ManagementException;
+import com.microsoft.azure.functions.annotation.AuthorizationLevel;
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
+import com.microsoft.azure.toolkit.lib.appservice.entity.FunctionEntity;
+import com.microsoft.azure.toolkit.lib.appservice.model.FunctionDeployType;
+import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionApp;
+import com.microsoft.azure.toolkit.lib.appservice.service.IFunctionAppBase;
+import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
+import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.zeroturnaround.zip.ZipUtil;
+import reactor.core.publisher.Mono;
+import reactor.core.scheduler.Schedulers;
+import reactor.util.retry.Retry;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.time.Duration;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+public class DeployFunctionAppTask extends AzureTask> {
+
+ private static final int SYNC_FUNCTION_MAX_ATTEMPTS = 5;
+ private static final int SYNC_FUNCTION_DELAY = 1;
+ private static final int LIST_TRIGGERS_MAX_RETRY = 5;
+ private static final int LIST_TRIGGERS_RETRY_PERIOD_IN_SECONDS = 10;
+ private static final String RUNNING = "Running";
+ private static final String AUTH_LEVEL = "authLevel";
+ private static final String HTTP_TRIGGER = "httpTrigger";
+ private static final String LOCAL_SETTINGS_FILE = "local.settings.json";
+ private static final String DEPLOY_START = "Starting deployment...";
+ private static final String DEPLOY_FINISH = "Deployment done, you may access your resource through %s";
+ private static final String HTTP_TRIGGER_URLS = "HTTP Trigger Urls:";
+ private static final String NO_ANONYMOUS_HTTP_TRIGGER = "No anonymous HTTP Triggers found in deployed function app, skip list triggers.";
+ private static final String NO_TRIGGERS_FOUNDED = "No triggers found in deployed function app, " +
+ "please try recompile the project by `mvn clean package` and deploy again.";
+ private static final String UNABLE_TO_LIST_NONE_ANONYMOUS_HTTP_TRIGGERS = "Some http trigger urls cannot be displayed " +
+ "because they are non-anonymous. To access the non-anonymous triggers, please refer to https://aka.ms/azure-functions-key.";
+ private static final String SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE = "Skip deployment for docker app service";
+ private static final String FAILED_TO_LIST_TRIGGERS = "Deployment succeeded, but failed to list http trigger urls.";
+ private static final String SYNC_TRIGGERS = "Syncing triggers and fetching function information";
+ private static final String LIST_TRIGGERS = "Querying triggers...";
+ private static final String LIST_TRIGGERS_WITH_RETRY = "Querying triggers (Attempt {0}/{1})...";
+
+ private final IFunctionAppBase> target;
+ private final File stagingDirectory;
+ private final FunctionDeployType deployType;
+
+ public DeployFunctionAppTask(@Nonnull IFunctionAppBase> target, @Nonnull File stagingFolder, @Nullable FunctionDeployType deployType) {
+ this.target = target;
+ this.stagingDirectory = stagingFolder;
+ this.deployType = deployType;
+ }
+
+ @Override
+ public AzureString getTitle() {
+ return AzureString.format("Deploy artifact to function app %s", target.name());
+ }
+
+ @Override
+ public IFunctionAppBase> execute() {
+ if (target.getRuntime().isDocker()) {
+ AzureMessager.getMessager().info(SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE);
+ return target;
+ }
+ deployArtifact();
+ if (target instanceof IFunctionApp) {
+ listHTTPTriggerUrls((IFunctionApp) target);
+ }
+ return target;
+ }
+
+ private void deployArtifact() {
+ AzureMessager.getMessager().info(DEPLOY_START);
+ // For ftp deploy, we need to upload entire staging directory not the zipped package
+ final File file = deployType == FunctionDeployType.FTP ? stagingDirectory : packageStagingDirectory();
+ final long startTime = System.currentTimeMillis();
+ if (deployType == null) {
+ target.deploy(file);
+ } else {
+ target.deploy(file, deployType);
+ }
+ AzureTelemetry.getActionContext().setProperty("deploy-cost", String.valueOf(System.currentTimeMillis() - startTime));
+ if (!StringUtils.equalsIgnoreCase(target.state(), RUNNING)) {
+ target.start();
+ }
+ AzureMessager.getMessager().info(String.format(DEPLOY_FINISH, target.hostName()));
+ }
+
+ private File packageStagingDirectory() {
+ try {
+ final File zipFile = Files.createTempFile("azure-functions", ".zip").toFile();
+ ZipUtil.pack(stagingDirectory, zipFile);
+ ZipUtil.removeEntry(zipFile, LOCAL_SETTINGS_FILE);
+ return zipFile;
+ } catch (IOException e) {
+ throw new AzureToolkitRuntimeException("Failed to package function to deploy", e);
+ }
+ }
+
+ private void listHTTPTriggerUrls(IFunctionApp target) {
+ try {
+ syncTriggers(target);
+ final List triggers = listFunctions(target);
+ final List httpFunction = triggers.stream()
+ .filter(function -> function.getTrigger() != null &&
+ StringUtils.equalsIgnoreCase(function.getTrigger().getType(), HTTP_TRIGGER))
+ .collect(Collectors.toList());
+ final List anonymousTriggers = httpFunction.stream()
+ .filter(bindingResource -> bindingResource.getTrigger() != null &&
+ StringUtils.equalsIgnoreCase(bindingResource.getTrigger().getProperty(AUTH_LEVEL), AuthorizationLevel.ANONYMOUS.toString()))
+ .collect(Collectors.toList());
+ if (CollectionUtils.isEmpty(httpFunction) || CollectionUtils.isEmpty(anonymousTriggers)) {
+ AzureMessager.getMessager().info(NO_ANONYMOUS_HTTP_TRIGGER);
+ return;
+ }
+ AzureMessager.getMessager().info(HTTP_TRIGGER_URLS);
+ anonymousTriggers.forEach(trigger -> AzureMessager.getMessager().info(String.format("\t %s : %s", trigger.getName(), trigger.getTriggerUrl())));
+ if (anonymousTriggers.size() < httpFunction.size()) {
+ AzureMessager.getMessager().info(UNABLE_TO_LIST_NONE_ANONYMOUS_HTTP_TRIGGERS);
+ }
+ } catch (final RuntimeException | InterruptedException e) {
+ // show warning instead of exception for list triggers
+ AzureMessager.getMessager().warning(FAILED_TO_LIST_TRIGGERS);
+ }
+ }
+
+ // todo: move to app service library
+ // Refers https://github.com/Azure/azure-functions-core-tools/blob/3.0.3568/src/Azure.Functions.Cli/Actions/AzureActions/PublishFunctionAppAction.cs#L452
+ private void syncTriggers(final IFunctionApp functionApp) throws InterruptedException {
+ AzureMessager.getMessager().info(SYNC_TRIGGERS);
+ Thread.sleep(5 * 1000);
+ Mono.fromRunnable(() -> {
+ try {
+ Azure.az(AzureAppService.class).getAppServiceManager(functionApp.subscriptionId())
+ .functionApps().manager().serviceClient().getWebApps().syncFunctions(functionApp.resourceGroup(), functionApp.name());
+ } catch (ManagementException e) {
+ if (e.getResponse().getStatusCode() == 200) {
+ // Java SDK throw exception with 200 response, swallow exception in this case
+ }
+ }
+ }).subscribeOn(Schedulers.boundedElastic())
+ .retryWhen(Retry.fixedDelay(SYNC_FUNCTION_MAX_ATTEMPTS - 1, Duration.ofSeconds(SYNC_FUNCTION_DELAY))).block();
+ }
+
+ private List listFunctions(final IFunctionApp functionApp) {
+ final int[] count = {0};
+ return Mono.fromCallable(() -> {
+ final AzureString message = count[0]++ == 0 ?
+ AzureString.fromString(LIST_TRIGGERS) : AzureString.format(LIST_TRIGGERS_WITH_RETRY, count[0], LIST_TRIGGERS_MAX_RETRY);
+ AzureMessager.getMessager().info(message);
+ return Optional.ofNullable(functionApp.listFunctions(true))
+ .filter(CollectionUtils::isNotEmpty)
+ .orElseThrow(() -> new AzureToolkitRuntimeException(NO_TRIGGERS_FOUNDED));
+ }).subscribeOn(Schedulers.boundedElastic())
+ .retryWhen(Retry.fixedDelay(LIST_TRIGGERS_MAX_RETRY - 1, Duration.ofSeconds(LIST_TRIGGERS_RETRY_PERIOD_IN_SECONDS))).block();
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployWebAppTask.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployWebAppTask.java
index 9de0cceb9e..186f9ab612 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployWebAppTask.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/task/DeployWebAppTask.java
@@ -6,19 +6,20 @@
package com.microsoft.azure.toolkit.lib.appservice.task;
import com.microsoft.azure.toolkit.lib.appservice.model.WebAppArtifact;
-import com.microsoft.azure.toolkit.lib.appservice.service.IWebApp;
+import com.microsoft.azure.toolkit.lib.appservice.service.IWebAppBase;
import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
-public class DeployWebAppTask extends AzureTask {
+public class DeployWebAppTask extends AzureTask> {
private static final String SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE = "Skip deployment for docker webapp, " +
"you can navigate to %s to access your docker webapp.";
private static final String DEPLOY_START = "Trying to deploy artifact to %s...";
@@ -28,15 +29,15 @@ public class DeployWebAppTask extends AzureTask {
private static final String STOP_APP_DONE = "Successfully stopped Web App.";
private static final String START_APP_DONE = "Successfully started Web App.";
private static final String RUNNING = "Running";
- private IWebApp webApp;
- private List artifacts;
- private boolean isStopAppDuringDeployment;
+ private final IWebAppBase> webApp;
+ private final List artifacts;
+ private final boolean isStopAppDuringDeployment;
- public DeployWebAppTask(IWebApp webApp, List artifacts) {
+ public DeployWebAppTask(IWebAppBase> webApp, List artifacts) {
this(webApp, artifacts, false);
}
- public DeployWebAppTask(IWebApp webApp, List artifacts, boolean isStopAppDuringDeployment) {
+ public DeployWebAppTask(IWebAppBase> webApp, List artifacts, boolean isStopAppDuringDeployment) {
this.webApp = webApp;
this.artifacts = artifacts;
this.isStopAppDuringDeployment = isStopAppDuringDeployment;
@@ -44,7 +45,7 @@ public DeployWebAppTask(IWebApp webApp, List artifacts, boolean
@Override
@AzureOperation(name = "webapp.deploy", params = {"this.webApp.entity().getName()"}, type = AzureOperation.Type.SERVICE)
- public IWebApp execute() {
+ public IWebAppBase> execute() {
if (webApp.getRuntime().isDocker()) {
AzureMessager.getMessager().info(AzureString.format(SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE, "https://" + webApp.hostName()));
return webApp;
@@ -66,14 +67,15 @@ private void deployArtifacts() {
if (artifacts.stream().anyMatch(artifact -> artifact.getDeployType() == null)) {
throw new AzureToolkitRuntimeException("missing deployment type for some artifacts.");
}
-
+ final long startTime = System.currentTimeMillis();
final List artifactsOneDeploy = this.artifacts.stream()
.filter(artifact -> artifact.getDeployType() != null)
.collect(Collectors.toList());
artifactsOneDeploy.forEach(resource -> webApp.deploy(resource.getDeployType(), resource.getFile(), resource.getPath()));
+ AzureTelemetry.getActionContext().setProperty("deploy-cost", String.valueOf(System.currentTimeMillis() - startTime));
}
- private static void stopAppService(IWebApp target) {
+ private static void stopAppService(IWebAppBase> target) {
AzureMessager.getMessager().info(STOP_APP);
target.stop();
// workaround for the resources release problem.
@@ -86,7 +88,7 @@ private static void stopAppService(IWebApp target) {
AzureMessager.getMessager().info(STOP_APP_DONE);
}
- private static void startAppService(IWebApp target) {
+ private static void startAppService(IWebAppBase> target) {
if (!StringUtils.equalsIgnoreCase(target.state(), RUNNING)) {
AzureMessager.getMessager().info(START_APP);
target.start();
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/AppServiceConfigUtils.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/AppServiceConfigUtils.java
new file mode 100644
index 0000000000..f8632104b2
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/AppServiceConfigUtils.java
@@ -0,0 +1,102 @@
+/*
+ * 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.toolkit.lib.appservice.utils;
+
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
+import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig;
+import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
+import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppService;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+import com.microsoft.azure.toolkit.lib.legacy.appservice.AppServiceUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.Map;
+
+import static com.microsoft.azure.toolkit.lib.appservice.utils.Utils.mergeObjects;
+
+public class AppServiceConfigUtils {
+ private static final String SETTING_DOCKER_IMAGE = "DOCKER_CUSTOM_IMAGE_NAME";
+ private static final String SETTING_REGISTRY_SERVER = "DOCKER_REGISTRY_SERVER_URL";
+
+ public static AppServiceConfig fromAppService(IAppService> appService, IAppServicePlan servicePlan) {
+ AppServiceConfig config = new AppServiceConfig();
+ config.appName(appService.name());
+
+ config.resourceGroup(appService.entity().getResourceGroup());
+ config.subscriptionId(Utils.getSubscriptionId(appService.id()));
+ config.region(appService.entity().getRegion());
+ config.pricingTier(servicePlan.entity().getPricingTier());
+ RuntimeConfig runtimeConfig = new RuntimeConfig();
+ if (AppServiceUtils.isDockerAppService(appService)) {
+ runtimeConfig.os(OperatingSystem.DOCKER);
+ final Map settings = appService.entity().getAppSettings();
+
+ final String imageSetting = settings.get(SETTING_DOCKER_IMAGE);
+ if (StringUtils.isNotBlank(imageSetting)) {
+ runtimeConfig.image(imageSetting);
+ } else {
+ runtimeConfig.image(appService.entity().getDockerImageName());
+ }
+ final String registryServerSetting = settings.get(SETTING_REGISTRY_SERVER);
+ if (StringUtils.isNotBlank(registryServerSetting)) {
+ runtimeConfig.registryUrl(registryServerSetting);
+ }
+ } else {
+ runtimeConfig.os(appService.getRuntime().getOperatingSystem());
+ runtimeConfig.webContainer(appService.getRuntime().getWebContainer());
+ runtimeConfig.javaVersion(appService.getRuntime().getJavaVersion());
+ }
+ config.runtime(runtimeConfig);
+ if (servicePlan.entity() != null) {
+ config.pricingTier(servicePlan.entity().getPricingTier());
+ config.servicePlanName(servicePlan.name());
+ config.servicePlanResourceGroup(servicePlan.entity().getResourceGroup());
+ }
+ return config;
+ }
+
+ public static AppServiceConfig buildDefaultWebAppConfig(String subscriptionId, String resourceGroup, String appName, String packaging, JavaVersion javaVersion) {
+ final AppServiceConfig appServiceConfig = AppServiceConfig.buildDefaultWebAppConfig(resourceGroup, appName, packaging, javaVersion);
+ final List regions = Azure.az(AzureAppService.class).listSupportedRegions(subscriptionId);
+ // replace with first region when the default region is not present
+ appServiceConfig.region(Utils.selectFirstOptionIfCurrentInvalid("region", regions, appServiceConfig.region()));
+ return appServiceConfig;
+ }
+
+ public static AppServiceConfig buildDefaultFunctionConfig(String subscriptionId, String resourceGroup, String appName, JavaVersion javaVersion) {
+ final AppServiceConfig appServiceConfig = AppServiceConfig.buildDefaultFunctionConfig(resourceGroup, appName, javaVersion);
+ final List regions = Azure.az(AzureAppService.class).listSupportedRegions(subscriptionId);
+ // replace with first region when the default region is not present
+ appServiceConfig.region(Utils.selectFirstOptionIfCurrentInvalid("region", regions, appServiceConfig.region()));
+ return appServiceConfig;
+ }
+
+ public static void mergeAppServiceConfig(AppServiceConfig to, AppServiceConfig from) {
+ try {
+ mergeObjects(to, from);
+ } catch (IllegalAccessException e) {
+ throw new AzureToolkitRuntimeException("Cannot copy object for class AppServiceConfig.", e);
+ }
+
+ if (to.runtime() != from.runtime()) {
+ mergeRuntime(to.runtime(), from.runtime());
+ }
+ }
+
+ private static void mergeRuntime(RuntimeConfig to, RuntimeConfig from) {
+ try {
+ mergeObjects(to, from);
+ } catch (IllegalAccessException e) {
+ throw new AzureToolkitRuntimeException("Cannot copy object for class RuntimeConfig.", e);
+ }
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/Utils.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/Utils.java
index ff69c3ed06..9ffa3f7c96 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/Utils.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/appservice/utils/Utils.java
@@ -12,10 +12,12 @@
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -60,4 +62,27 @@ public static DeployType getDeployTypeByFileExtension(File file) {
throw new AzureToolkitRuntimeException("Unsupported file type, please set the deploy type.");
}
}
+
+ public static T selectFirstOptionIfCurrentInvalid(String name, List options, T value) {
+ if (options.isEmpty()) {
+ throw new AzureToolkitRuntimeException(String.format("No %s is available.", name));
+ }
+ return options.contains(value) ? value : options.get(0);
+ }
+
+ public static void mergeObjects(T to, T from) throws IllegalAccessException {
+ for (Field field : FieldUtils.getAllFields(from.getClass())) {
+ if (FieldUtils.readField(field, to, true) == null) {
+ final Object value = FieldUtils.readField(field, from, true);
+ if (value != null) {
+ FieldUtils.writeField(field, to, value, true);
+ }
+ }
+ }
+ }
+
+ public static void throwForbidCreateResourceWarning(String resourceType, String name) {
+ throw new AzureToolkitRuntimeException(String.format("%s(%s) cannot be found, if you want to create azure resources please remove command line arguments: " +
+ "`-Dazure.resource.create.skip=true` or `-DskipCreateAzureResource`.", resourceType, name));
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/legacy/appservice/AppServiceUtils.java b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/legacy/appservice/AppServiceUtils.java
index a766fe6c1e..0914599bad 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/legacy/appservice/AppServiceUtils.java
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/java/com/microsoft/azure/toolkit/lib/legacy/appservice/AppServiceUtils.java
@@ -7,7 +7,7 @@
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
-import com.microsoft.azure.toolkit.lib.appservice.service.IWebApp;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppService;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
@@ -41,8 +41,8 @@ public static DockerImageType getDockerImageType(final String imageName, final b
}
}
- public static boolean isDockerAppService(IWebApp webapp) {
- return webapp != null && webapp.getRuntime() != null && webapp.getRuntime().isDocker();
+ public static boolean isDockerAppService(IAppService> appService) {
+ return appService != null && appService.getRuntime() != null && appService.getRuntime().isDocker();
}
}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/appservice.properties b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/appservice.properties
index e0efebd1d2..f5cecf0a35 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/appservice.properties
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/appservice.properties
@@ -11,3 +11,4 @@ appservice|deployment.get.id=get Azure App Service deployment slot by id({0})
appservice|deployment.get.name|app|rg|subscription=get Azure App Service deployment slot({0}) of app({1})
appservice.get_client.subscription=get Azure App Service rest client of subscription({0})
appservice|plan.create_update=create or update Azure App Service plan ({0}) from config
+appservice.check_name=check name availability for ({0})
\ No newline at end of file
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/functionapp.properties b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/functionapp.properties
index c6a2d3119f..4aa54379f1 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/functionapp.properties
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/functionapp.properties
@@ -2,3 +2,4 @@ functionapp.get.id=get Azure Functions app({0})
functionapp.get.name|rg|sid=get Azure Functions app({0}) in resource group{(1)}
functionapp.list.subscription|selected=list Azure Functions apps of selected subscriptions
functionapp.list.subscription=list Azure Functions apps of subscription({0})
+functionapp|mojo.deploy=deploy to Azure Function App with resource creation or updating
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/webapp.properties b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/webapp.properties
index 2fbadd240c..875251e16f 100644
--- a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/webapp.properties
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/webapp.properties
@@ -5,5 +5,6 @@ webapp.get.name|rg|sid=get Azure Web App({0}) in resource group({1})
webapp.list.subscription|selected=list Azure Web Apps of selected subscriptions
webapp.list.subscription=list Azure Web Apps of subscription({0})
webapp|runtime.list.os|version=list available Azure Web App runtimes with os({0}) and java version({1})
+webapp|mojo.deploy=deploy to Azure Web App with resource creation or updating
webapp.create=create Azure Web App ({0}) from config
webapp.update=update Azure Web App ({0}) from config
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/AppServicePlan.json b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/AppServicePlan.json
new file mode 100644
index 0000000000..109cd55b80
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/AppServicePlan.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "App Service Plan - Update",
+ "description": "Schema for AppServicePlanConfig when update existing service plan",
+ "properties": {
+ "subscriptionId": {
+ "$ref": "classpath:///schema/common/UUID.json"
+ },
+ "servicePlanResourceGroup": {
+ "$ref": "classpath:///schema/common/ResourceGroupName.json"
+ },
+ "servicePlanName": {
+ "$ref": "classpath:///schema/appservice/AppServicePlanName.json"
+ },
+ "os": {
+ "$ref": "classpath:///schema/appservice/Runtime.json#/definitions/os"
+ },
+ "region": {
+ "type": "object"
+ },
+ "pricingTier": {
+ "type": "object"
+ }
+ },
+ "required": [
+ "subscriptionId",
+ "servicePlanName",
+ "servicePlanResourceGroup"
+ ]
+}
diff --git a/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/CreateAppServicePlan.json b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/CreateAppServicePlan.json
new file mode 100644
index 0000000000..9671330f7f
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-appservice-lib/src/main/resources/schema/appservice/CreateAppServicePlan.json
@@ -0,0 +1,10 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "App Service Plan - Update",
+ "description": "Schema for AppServicePlanConfig when update existing service plan",
+ "allOf": [
+ {
+ "$ref": "classpath:///schema/appservice/AppServicePlan.json"
+ }
+ ]
+}
diff --git a/azure-toolkit-libs/azure-toolkit-auth-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-auth-lib/pom.xml
index 4d01040b2c..4d0f6549f7 100644
--- a/azure-toolkit-libs/azure-toolkit-auth-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-auth-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
@@ -15,14 +15,6 @@
com.azure
azure-core
-
- com.azure
- azure-core-http-okhttp
-
-
- com.squareup.okhttp3
- okhttp
-
org.apache.commons
commons-lang3
@@ -63,11 +55,6 @@
com.microsoft.azure
azure-client-runtime
-
- com.azure.resourcemanager
- azure-resourcemanager
-
-
com.azure
azure-identity
diff --git a/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/AzureAccount.java b/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/AzureAccount.java
index d7a6f3b9c2..eefa75186d 100644
--- a/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/AzureAccount.java
+++ b/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/AzureAccount.java
@@ -6,22 +6,15 @@
package com.microsoft.azure.toolkit.lib.auth;
import com.azure.core.credential.TokenCredential;
-import com.azure.core.http.policy.HttpLogDetailLevel;
-import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.management.AzureEnvironment;
-import com.azure.core.management.profile.AzureProfile;
import com.azure.identity.SharedTokenCacheCredential;
import com.azure.identity.SharedTokenCacheCredentialBuilder;
import com.azure.identity.TokenCachePersistenceOptions;
-import com.azure.resourcemanager.AzureResourceManager;
-import com.azure.resourcemanager.resources.fluentcore.policy.ProviderRegistrationPolicy;
import com.azure.resourcemanager.resources.models.Location;
-import com.azure.resourcemanager.resources.models.Providers;
import com.azure.resourcemanager.resources.models.RegionType;
import com.azure.resourcemanager.resources.models.Subscription;
import com.google.common.base.Preconditions;
import com.microsoft.azure.toolkit.lib.Azure;
-import com.microsoft.azure.toolkit.lib.AzureConfiguration;
import com.microsoft.azure.toolkit.lib.account.IAzureAccount;
import com.microsoft.azure.toolkit.lib.auth.core.azurecli.AzureCliAccount;
import com.microsoft.azure.toolkit.lib.auth.core.devicecode.DeviceCodeAccount;
@@ -241,7 +234,8 @@ public List listRegions(String subscriptionId) {
* see doc for: az account list-locations -o table
*/
public List listRegions() {
- return Flux.fromIterable(getSubscriptions()).parallel().map(com.microsoft.azure.toolkit.lib.common.model.Subscription::getId)
+ return Flux.fromIterable(Azure.az(IAzureAccount.class).account().getSelectedSubscriptions())
+ .parallel().map(com.microsoft.azure.toolkit.lib.common.model.Subscription::getId)
.map(this::listRegions)
.sequential().collectList()
.map(regionSet -> regionSet.stream()
@@ -276,37 +270,7 @@ private static Map> buildAccountMap() {
// todo: share codes with other library which leverage track2 mgmt sdk
@Cacheable(cacheName = "Subscription", key = "$subscriptionId")
private Subscription getSubscription(String subscriptionId) {
- return getAzureResourceManager(subscriptionId).subscriptions().getById(subscriptionId);
+ return getResourceManager(subscriptionId).subscriptions().getById(subscriptionId);
}
- // todo: share codes with other library which leverage track2 mgmt sdk
- @Cacheable(cacheName = "AzureResourceManager", key = "$subscriptionId")
- private AzureResourceManager getAzureResourceManager(String subscriptionId) {
- // make sure it is signed in.
- account();
- final AzureConfiguration config = Azure.az().config();
- final String userAgent = config.getUserAgent();
- final HttpLogDetailLevel logDetailLevel = config.getLogLevel() == null ?
- HttpLogDetailLevel.NONE : HttpLogDetailLevel.valueOf(config.getLogLevel());
- final AzureProfile azureProfile = new AzureProfile(account.getEnvironment());
-
- final Providers providers = AzureResourceManager.configure()
- .withPolicy(getUserAgentPolicy(userAgent))
- .authenticate(account.getTokenCredential(subscriptionId), azureProfile)
- .withSubscription(subscriptionId).providers();
- return AzureResourceManager.configure()
- .withLogLevel(logDetailLevel)
- .withPolicy(getUserAgentPolicy(userAgent)) // set user agent with policy
- .withPolicy(new ProviderRegistrationPolicy(providers)) // add policy to auto register resource providers
- .authenticate(account.getTokenCredential(subscriptionId), azureProfile)
- .withSubscription(subscriptionId);
- }
-
- private HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
- return (httpPipelineCallContext, httpPipelineNextPolicy) -> {
- final String previousUserAgent = httpPipelineCallContext.getHttpRequest().getHeaders().getValue("User-Agent");
- httpPipelineCallContext.getHttpRequest().setHeader("User-Agent", String.format("%s %s", userAgent, previousUserAgent));
- return httpPipelineNextPolicy.process();
- };
- }
}
diff --git a/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/TokenCredentialManager.java b/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/TokenCredentialManager.java
index 0bb9a2f2bd..9b46c2938f 100644
--- a/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/TokenCredentialManager.java
+++ b/azure-toolkit-libs/azure-toolkit-auth-lib/src/main/java/com/microsoft/azure/toolkit/lib/auth/TokenCredentialManager.java
@@ -6,18 +6,16 @@
package com.microsoft.azure.toolkit.lib.auth;
import com.azure.core.credential.TokenCredential;
-import com.azure.core.http.ProxyOptions;
-import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder;
import com.azure.core.http.policy.FixedDelay;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.policy.RetryPolicy;
import com.azure.core.management.AzureEnvironment;
import com.azure.core.management.profile.AzureProfile;
import com.azure.core.util.logging.ClientLogger;
-import com.azure.resourcemanager.AzureResourceManager;
+import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.models.Tenant;
import com.microsoft.azure.toolkit.lib.Azure;
-import com.microsoft.azure.toolkit.lib.AzureConfiguration;
+import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
import com.microsoft.azure.toolkit.lib.common.utils.Utils;
import lombok.Getter;
@@ -27,7 +25,6 @@
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
-import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
@@ -70,7 +67,7 @@ public Mono> listSubscriptions(List tenantIds) {
.collect(Collectors.toList()));
}
- private static Mono> listSubscriptionsInTenant(AzureResourceManager.Authenticated client, String tenantId) {
+ private static Mono> listSubscriptionsInTenant(ResourceManager.Authenticated client, String tenantId) {
return client.subscriptions().listAsync()
.map(s -> toSubscriptionEntity(tenantId, s)).collectList().onErrorResume(ex -> {
// warn and ignore, should modify here if IMessage is ready
@@ -89,35 +86,23 @@ private static Subscription toSubscriptionEntity(String tenantId,
return subscriptionEntity;
}
- private AzureResourceManager.Authenticated createAzureClient(AzureEnvironment env, String tenantId) {
+ private ResourceManager.Authenticated createAzureClient(AzureEnvironment env, String tenantId) {
AzureProfile profile = new AzureProfile(env);
return configureAzure().authenticate(this.createTokenCredentialForTenant(tenantId), profile);
}
- private AzureResourceManager.Authenticated createAzureClient(AzureEnvironment env) {
+ private ResourceManager.Authenticated createAzureClient(AzureEnvironment env) {
AzureProfile profile = new AzureProfile(env);
return configureAzure().authenticate(this.rootCredentialSupplier.get(), profile);
}
/**
- * TODO: share the same code for creating AzureResourceManager.Configurable
+ * TODO: share the same code for creating ResourceManager.Configurable
*/
- private static AzureResourceManager.Configurable configureAzure() {
- OkHttpAsyncHttpClientBuilder builder = new OkHttpAsyncHttpClientBuilder();
- final AzureConfiguration config = Azure.az().config();
- if (StringUtils.isNotBlank(config.getProxySource())) {
- final ProxyOptions proxyOptions = new ProxyOptions(ProxyOptions.Type.HTTP,
- new InetSocketAddress(config.getHttpProxyHost(), config.getHttpProxyPort())
- );
- if (StringUtils.isNoneBlank(config.getProxyUsername(), config.getProxyPassword())) {
- proxyOptions.setCredentials(config.getProxyUsername(), config.getProxyPassword());
- }
- builder.proxy(proxyOptions);
- }
-
+ private static ResourceManager.Configurable configureAzure() {
// disable retry for getting tenant and subscriptions
- return AzureResourceManager.configure()
- .withHttpClient(builder.build())
+ return ResourceManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withPolicy(createUserAgentPolicy())
.withRetryPolicy(new RetryPolicy(new FixedDelay(0, Duration.ofSeconds(0))));
}
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-common-lib/pom.xml
index 42c0f195df..baa433b3b9 100644
--- a/azure-toolkit-libs/azure-toolkit-common-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/pom.xml
@@ -5,13 +5,17 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
azure-toolkit-common-lib
+
+ com.azure
+ azure-core-http-netty
+
com.networknt
json-schema-validator
@@ -84,10 +88,6 @@
org.reflections
reflections
-
- com.squareup.okhttp3
- okhttp
-
org.apache.httpcomponents
httpclient
@@ -120,6 +120,15 @@
+
+
+ src/main/resources
+ true
+
+ schema/**/*.json
+
+
+
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/AzureService.java b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/AzureService.java
index 0b6d63ecd1..a844d0fa72 100644
--- a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/AzureService.java
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/AzureService.java
@@ -5,22 +5,124 @@
package com.microsoft.azure.toolkit.lib;
+import com.azure.core.http.HttpClient;
+import com.azure.core.http.ProxyOptions;
+import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
+import com.azure.core.http.policy.HttpLogDetailLevel;
+import com.azure.core.http.policy.HttpPipelinePolicy;
+import com.azure.core.management.profile.AzureProfile;
+import com.azure.resourcemanager.resources.ResourceManager;
+import com.azure.resourcemanager.resources.fluentcore.policy.ProviderRegistrationPolicy;
+import com.azure.resourcemanager.resources.models.ProviderResourceType;
+import com.azure.resourcemanager.resources.models.Providers;
+import com.microsoft.azure.toolkit.lib.account.IAccount;
import com.microsoft.azure.toolkit.lib.account.IAzureAccount;
+import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
+import com.microsoft.azure.toolkit.lib.common.entity.IAzureBaseResource;
+import com.microsoft.azure.toolkit.lib.common.entity.IAzureModule;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
-import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
+import io.netty.resolver.AddressResolverGroup;
+import io.netty.resolver.DefaultAddressResolverGroup;
+import io.netty.resolver.NoopAddressResolverGroup;
+import org.apache.commons.lang3.StringUtils;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
-public interface AzureService {
+import static com.microsoft.azure.toolkit.lib.Azure.az;
+
+public interface AzureService extends IAzureModule {
default List getSubscriptions() {
return Azure.az(IAzureAccount.class).account().getSelectedSubscriptions();
}
- default String name() {
- return this.getClass().getSimpleName();
+ default List listSupportedRegions(String subscriptionId) {
+ String[] names = StringUtils.split(name(), "/");
+ if (names.length != 2) {
+ throw new AzureToolkitRuntimeException(String.format("It is illegal to list regions for service '%s'.", name()));
+ }
+ final String provider = names[0];
+ final String resourceType = names[1];
+ List allRegionList = az(IAzureAccount.class).listRegions(subscriptionId);
+ List result = new ArrayList<>();
+ final ResourceManager resourceManager = getResourceManager(subscriptionId);
+ resourceManager.providers().getByName(provider).resourceTypes()
+ .stream().filter(type -> StringUtils.equalsIgnoreCase(type.resourceType(), resourceType))
+ .findAny().map(ProviderResourceType::locations)
+ .ifPresent(list -> result.addAll(list.stream().map(Region::fromName).filter(allRegionList::contains).collect(Collectors.toList())));
+ return result.isEmpty() ? allRegionList : result;
+ }
+
+ @Cacheable(cacheName = "resource/{}/manager", key = "$subscriptionId")
+ default ResourceManager getResourceManager(String subscriptionId) {
+ // make sure it is signed in.
+ final IAccount account = az(IAzureAccount.class).account();
+ final AzureConfiguration config = Azure.az().config();
+ final String userAgent = config.getUserAgent();
+ final HttpLogDetailLevel logDetailLevel = config.getLogLevel() == null ?
+ HttpLogDetailLevel.NONE : HttpLogDetailLevel.valueOf(config.getLogLevel());
+ final AzureProfile azureProfile = new AzureProfile(account.getEnvironment());
+
+ final Providers providers = ResourceManager.configure()
+ .withHttpClient(getDefaultHttpClient())
+ .withPolicy(getUserAgentPolicy(userAgent))
+ .authenticate(account.getTokenCredential(subscriptionId), azureProfile)
+ .withSubscription(subscriptionId).providers();
+ return ResourceManager.configure()
+ .withHttpClient(getDefaultHttpClient())
+ .withLogLevel(logDetailLevel)
+ .withPolicy(getUserAgentPolicy(userAgent)) // set user agent with policy
+ .withPolicy(new ProviderRegistrationPolicy(providers)) // add policy to auto register resource providers
+ .authenticate(account.getTokenCredential(subscriptionId), azureProfile)
+ .withSubscription(subscriptionId);
+ }
+
+ static HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
+ return (httpPipelineCallContext, httpPipelineNextPolicy) -> {
+ final String previousUserAgent = httpPipelineCallContext.getHttpRequest().getHeaders().getValue("User-Agent");
+ httpPipelineCallContext.getHttpRequest().setHeader("User-Agent", String.format("%s %s", userAgent, previousUserAgent));
+ return httpPipelineNextPolicy.process();
+ };
+ }
+
+ class HttpClientHolder {
+ private static HttpClient defaultHttpClient = null;
+
+ private static synchronized HttpClient createHttpClient() {
+ if (defaultHttpClient != null) {
+ return defaultHttpClient;
+ }
+
+ AddressResolverGroup resolverGroup;
+ ProxyOptions proxyOptions = null;
+ final AzureConfiguration config = Azure.az().config();
+ if (StringUtils.isNotBlank(config.getProxySource())) {
+ proxyOptions = new ProxyOptions(ProxyOptions.Type.HTTP,
+ new InetSocketAddress(config.getHttpProxyHost(), config.getHttpProxyPort())
+ );
+ if (StringUtils.isNoneBlank(config.getProxyUsername(), config.getProxyPassword())) {
+ proxyOptions.setCredentials(config.getProxyUsername(), config.getProxyPassword());
+ }
+ resolverGroup = NoopAddressResolverGroup.INSTANCE;
+ } else {
+ resolverGroup = DefaultAddressResolverGroup.INSTANCE;
+ }
+ reactor.netty.http.client.HttpClient nettyHttpClient =
+ reactor.netty.http.client.HttpClient.create()
+ .resolver(resolverGroup);
+ NettyAsyncHttpClientBuilder builder = new NettyAsyncHttpClientBuilder(nettyHttpClient);
+ Optional.ofNullable(proxyOptions).map(proxy -> builder.proxy(proxy));
+ defaultHttpClient = builder.build();
+ return defaultHttpClient;
+ }
}
- @AzureOperation(name = "common|service.refresh", params = "this.name()", type = AzureOperation.Type.SERVICE)
- default void refresh() {
+ static HttpClient getDefaultHttpClient() {
+ return HttpClientHolder.createHttpClient();
}
}
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAccount.java b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAccount.java
index 2fa82565a9..7af0ecf00b 100644
--- a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAccount.java
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAccount.java
@@ -5,6 +5,8 @@
package com.microsoft.azure.toolkit.lib.account;
+import com.azure.core.credential.TokenCredential;
+import com.azure.core.management.AzureEnvironment;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
import java.util.List;
@@ -18,4 +20,8 @@ public interface IAccount {
Subscription getSubscription(String subscriptionId);
String portalUrl();
+
+ AzureEnvironment getEnvironment();
+
+ TokenCredential getTokenCredential(String subscriptionId);
}
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAzureAccount.java b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAzureAccount.java
index bf5049426a..79f69be988 100644
--- a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAzureAccount.java
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/account/IAzureAccount.java
@@ -6,7 +6,12 @@
package com.microsoft.azure.toolkit.lib.account;
import com.microsoft.azure.toolkit.lib.AzureService;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+
+import java.util.List;
public interface IAzureAccount extends AzureService {
IAccount account();
+
+ List listRegions(String subscriptionId);
}
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/Action.java b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/Action.java
new file mode 100644
index 0000000000..45a090a141
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/Action.java
@@ -0,0 +1,150 @@
+/*
+ * 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.toolkit.lib.common.action;
+
+import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
+import com.microsoft.azure.toolkit.lib.common.entity.IAzureBaseResource;
+import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
+import com.microsoft.azure.toolkit.lib.common.operation.IAzureOperation;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTaskManager;
+import com.microsoft.azure.toolkit.lib.common.telemetry.AzureTelemetry;
+import com.microsoft.azure.toolkit.lib.common.view.IView;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.AbstractMap;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.BiConsumer;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+@Accessors(chain = true, fluent = true)
+public class Action {
+ public static final String SOURCE = "ACTION_SOURCE";
+ public static final Id REQUIRE_AUTH = Id.of("action.common.requireAuth");
+ @Nonnull
+ private List, BiConsumer>> handlers = new ArrayList<>();
+ @Nullable
+ @Getter
+ private ActionView.Builder view;
+ @Setter
+ private boolean authRequired = true;
+
+ public Action(@Nullable ActionView.Builder view) {
+ this.view = view;
+ }
+
+ public Action(@Nonnull Consumer handler) {
+ this.registerHandler((d, e) -> true, (d, e) -> handler.accept(d));
+ }
+
+ public Action(@Nonnull BiConsumer handler) {
+ this.registerHandler((d, e) -> true, handler);
+ }
+
+ public Action(@Nonnull Consumer handler, @Nullable ActionView.Builder view) {
+ this.view = view;
+ this.registerHandler((d, e) -> true, (d, e) -> handler.accept(d));
+ }
+
+ public Action(@Nonnull BiConsumer handler, @Nullable ActionView.Builder view) {
+ this.view = view;
+ this.registerHandler((d, e) -> true, handler);
+ }
+
+ private Action(@Nonnull List, BiConsumer>> handlers, @Nullable ActionView.Builder view) {
+ this.view = view;
+ this.handlers = handlers;
+ }
+
+ @Nullable
+ public IView.Label view(D source) {
+ return Objects.nonNull(this.view) ? this.view.toActionView(source) : null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public BiConsumer handler(D source, Object e) {
+ for (int i = this.handlers.size() - 1; i >= 0; i--) {
+ final AbstractMap.SimpleEntry, BiConsumer> p = this.handlers.get(i);
+ final BiPredicate condition = (BiPredicate) p.getKey();
+ final BiConsumer handler = (BiConsumer) p.getValue();
+ if (condition.test(source, e)) {
+ return handler;
+ }
+ }
+ return null;
+ }
+
+ public void handle(D source, Object e) {
+ final Runnable runnable = () -> {
+ final BiConsumer handler = this.handler(source, e);
+ if (Objects.nonNull(handler)) {
+ final AzureString title = Optional.ofNullable(this.view).map(b -> b.title).map(t -> t.apply(source))
+ .orElse(AzureString.fromString(IAzureOperation.UNKNOWN_NAME));
+ final AzureTask task = new AzureTask<>(title, () -> handle(source, e, handler));
+ task.setType(AzureOperation.Type.ACTION.name());
+ AzureTaskManager.getInstance().runInBackground(task);
+ }
+ };
+ if (this.authRequired) {
+ final Action requireAuth = AzureActionManager.getInstance().getAction(REQUIRE_AUTH);
+ if (Objects.nonNull(requireAuth)) {
+ requireAuth.handle(runnable, e);
+ }
+ } else {
+ runnable.run();
+ }
+ }
+
+ protected void handle(D source, Object e, BiConsumer handler) {
+ if (source instanceof IAzureBaseResource) {
+ AzureTelemetry.getActionContext().setProperty("subscriptionId", ((IAzureBaseResource, ?>) source).subscriptionId());
+ AzureTelemetry.getActionContext().setProperty("resourceType", source.getClass().getSimpleName());
+ }
+ handler.accept(source, e);
+ }
+
+ public void handle(D source) {
+ this.handle(source, null);
+ }
+
+ public void registerHandler(@Nonnull Predicate condition, @Nonnull Consumer handler) {
+ this.handlers.add(new AbstractMap.SimpleEntry<>((d, e) -> condition.test(d), (d, e) -> handler.accept(d)));
+ }
+
+ public void registerHandler(@Nonnull BiPredicate condition, @Nonnull BiConsumer handler) {
+ this.handlers.add(new AbstractMap.SimpleEntry<>(condition, handler));
+ }
+
+ public static class Id {
+ @Nonnull
+ private final String id;
+
+ private Id(@Nonnull String id) {
+ this.id = id;
+ }
+
+ public static Id of(@Nonnull String id) {
+ assert StringUtils.isNotBlank(id) : "action id can not be blank";
+ return new Id<>(id);
+ }
+
+ @Nonnull
+ public String getId() {
+ return id;
+ }
+ }
+}
+
diff --git a/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/ActionGroup.java b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/ActionGroup.java
new file mode 100644
index 0000000000..5c6c39957e
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-common-lib/src/main/java/com/microsoft/azure/toolkit/lib/common/action/ActionGroup.java
@@ -0,0 +1,57 @@
+/*
+ * 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.toolkit.lib.common.action;
+
+import com.microsoft.azure.toolkit.lib.common.view.IView;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.List;
+
+@Getter
+@Accessors(chain = true, fluent = true)
+public class ActionGroup {
+ @Nullable
+ private IView.Label view;
+ private final List
-
\ No newline at end of file
+
diff --git a/azure-toolkit-libs/azure-toolkit-mysql-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-mysql-lib/pom.xml
index 4b27002c93..e88ecd81b8 100644
--- a/azure-toolkit-libs/azure-toolkit-mysql-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-mysql-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
diff --git a/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/AzureMySql.java b/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/AzureMySql.java
index f0107aa9b9..3c12d04569 100644
--- a/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/AzureMySql.java
+++ b/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/AzureMySql.java
@@ -15,7 +15,6 @@
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.SubscriptionScoped;
-import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
import com.microsoft.azure.toolkit.lib.common.model.Region;
@@ -27,20 +26,11 @@
import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nonnull;
-import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
-import static com.microsoft.azure.toolkit.lib.Azure.az;
-
public class AzureMySql extends SubscriptionScoped implements AzureService {
- private static final List MYSQL_SUPPORTED_REGIONS = Arrays.asList(
- "australiacentral", "australiacentral2", "australiaeast", "australiasoutheast", "brazilsouth", "canadacentral", "canadaeast", "centralindia",
- "centralus", "eastasia", "eastus2", "eastus", "francecentral", "francesouth", "germanywestcentral", "japaneast", "japanwest", "koreacentral",
- "koreasouth", "northcentralus", "northeurope", "southafricanorth", "southafricawest", "southcentralus", "southindia", "southeastasia",
- "norwayeast", "switzerlandnorth", "uaenorth", "uksouth", "ukwest", "westcentralus", "westeurope", "westindia", "westus", "westus2",
- "centraluseuap", "eastus2euap");
- private static final String NAME_AVAILABILITY_CHECK_TYPE = "Microsoft.DBforMySQL/servers";
+ private static final String MYSQL_PROVIDER_AND_RESOURCE = "Microsoft.DBforMySQL/servers";
public AzureMySql() {
super(AzureMySql::new);
@@ -80,16 +70,12 @@ private static int getTierPriority(PerformanceTierProperties tier) {
public boolean checkNameAvailability(String name) {
MySqlManager mySqlManager = MySqlManagerFactory.create(getDefaultSubscription().getId());
- NameAvailabilityRequest request = new NameAvailabilityRequest().withName(name).withType(NAME_AVAILABILITY_CHECK_TYPE);
+ NameAvailabilityRequest request = new NameAvailabilityRequest().withName(name).withType(MYSQL_PROVIDER_AND_RESOURCE);
return mySqlManager.checkNameAvailabilities().execute(request).nameAvailable();
}
public List listSupportedRegions() {
- List locationList = az(AzureAccount.class).listRegions(getDefaultSubscription().getId());
- return locationList.stream()
- .filter(e -> MYSQL_SUPPORTED_REGIONS.contains(e.getName()))
- .distinct()
- .collect(Collectors.toList());
+ return listSupportedRegions(getDefaultSubscription().getId());
}
public List listSupportedVersions() {
@@ -172,4 +158,8 @@ public AzureOperationEvent.Source getEventSource() {
return new AzureOperationEvent.Source() {};
}
}
+
+ public String name() {
+ return MYSQL_PROVIDER_AND_RESOURCE;
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/MySqlManagerFactory.java b/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/MySqlManagerFactory.java
index 73652c1c4a..aa7255a45c 100644
--- a/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/MySqlManagerFactory.java
+++ b/azure-toolkit-libs/azure-toolkit-mysql-lib/src/main/java/com/microsoft/azure/toolkit/lib/mysql/MySqlManagerFactory.java
@@ -11,6 +11,7 @@
import com.azure.resourcemanager.mysql.MySqlManager;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureConfiguration;
+import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
@@ -30,6 +31,7 @@ public static MySqlManager create(String subscriptionId) {
final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
final AzureProfile azureProfile = new AzureProfile(null, subscriptionId, account.getEnvironment());
return MySqlManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogOptions(new HttpLogOptions().setLogLevel(logLevel))
.withPolicy(getUserAgentPolicy(userAgent))
.authenticate(account.getTokenCredential(subscriptionId), azureProfile);
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-redis-lib/pom.xml
new file mode 100644
index 0000000000..c4d80b3bcf
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/pom.xml
@@ -0,0 +1,119 @@
+
+
+
+ azure-toolkit-libs
+ com.microsoft.azure
+ 0.12.1
+
+ 4.0.0
+
+ azure-toolkit-redis-lib
+
+
+
+
+ com.microsoft.azure
+ azure-toolkit-common-lib
+
+
+
+ com.microsoft.azure
+ azure-toolkit-auth-lib
+
+
+
+ org.projectlombok
+ lombok
+ provided
+
+
+
+ com.azure.resourcemanager
+ azure-resourcemanager-redis
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+
+
+ com.nickwongdev
+ aspectj-maven-plugin
+
+ false
+ 1.8
+ 1.8
+ ignore
+ 1.8
+ UTF-8
+ false
+ true
+ true
+
+
+
+ com.microsoft.azure
+ azure-toolkit-common-lib
+
+
+
+
+
+ compile-with-aspectj
+ process-classes
+
+
+ ${project.build.directory}/classes
+
+
+
+ compile
+
+
+
+ test-compile-with-aspectj
+ process-test-classes
+
+ test-compile
+
+
+
+ ${project.build.directory}/test-classes
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+ private
+ false
+
+
+
+ attach-javadocs
+
+ jar
+
+
+ ${javadoc.opts}
+
+
+
+
+
+
+
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/AzureRedis.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/AzureRedis.java
new file mode 100644
index 0000000000..bf126fce1a
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/AzureRedis.java
@@ -0,0 +1,110 @@
+/*
+ * 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.toolkit.redis;
+
+import com.azure.core.management.exception.ManagementError;
+import com.azure.core.management.exception.ManagementException;
+import com.azure.resourcemanager.redis.RedisManager;
+import com.azure.resourcemanager.redis.fluent.RedisClient;
+import com.azure.resourcemanager.redis.models.CheckNameAvailabilityParameters;
+import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
+import com.microsoft.azure.toolkit.lib.AzureService;
+import com.microsoft.azure.toolkit.lib.SubscriptionScoped;
+import com.microsoft.azure.toolkit.lib.common.entity.CheckNameAvailabilityResultEntity;
+import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
+import com.microsoft.azure.toolkit.lib.common.model.Subscription;
+import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
+import com.microsoft.azure.toolkit.lib.common.task.ICommittable;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class AzureRedis extends SubscriptionScoped implements AzureService, AzureOperationEvent.Source {
+ public AzureRedis() {
+ super(AzureRedis::new);
+ }
+
+ private AzureRedis(@Nonnull final List subscriptions) {
+ super(AzureRedis::new, subscriptions);
+ }
+
+ @Nonnull
+ @AzureOperation(name = "redis.list.subscription|selected", type = AzureOperation.Type.SERVICE)
+ public List list() {
+ return getSubscriptions().stream()
+ .map(subscription -> RedisManagerFactory.create(subscription.getId()))
+ .flatMap(manager -> manager.redisCaches().list().stream())
+ .map(redis -> new RedisCache(redis.manager(), redis))
+ .collect(Collectors.toList());
+ }
+
+ @AzureOperation(name = "redis.get.id", params = {"id"}, type = AzureOperation.Type.SERVICE)
+ public RedisCache get(@Nonnull String id) {
+ com.azure.resourcemanager.redis.models.RedisCache redisCache =
+ RedisManagerFactory.create(ResourceId.fromString(id).subscriptionId()).redisCaches().getById(id);
+ return new RedisCache(redisCache.manager(), redisCache);
+ }
+
+ @AzureOperation(name = "redis.check_name", params = "name", type = AzureOperation.Type.SERVICE)
+ public CheckNameAvailabilityResultEntity checkNameAvailability(String subscriptionId, String name) {
+ final RedisManager redisManager = RedisManagerFactory.create(subscriptionId);
+ RedisClient redis = redisManager.redisCaches().manager().serviceClient().getRedis();
+ try {
+ redis.checkNameAvailability(new CheckNameAvailabilityParameters().withName(name).withType("Microsoft.Cache/redis"));
+ return new CheckNameAvailabilityResultEntity(true, null);
+ } catch (ManagementException ex) {
+ ManagementError value = ex.getValue();
+ if (value != null && "NameNotAvailable".equals(value.getCode())) {
+ return new CheckNameAvailabilityResultEntity(false, String.format("The name '%s' for Redis Cache is not available", name), value.getMessage());
+ }
+ throw ex;
+ }
+ }
+
+ public RedisCache create(RedisConfig config) {
+ return new Creator(config).commit();
+ }
+
+ @AllArgsConstructor(access = AccessLevel.PRIVATE)
+ private static class Creator implements ICommittable, AzureOperationEvent.Source {
+
+ private final RedisConfig config;
+
+ @Override
+ @AzureOperation(name = "redis.create", params = {"this.config.getName()"}, type = AzureOperation.Type.SERVICE)
+ public RedisCache commit() {
+ final com.azure.resourcemanager.redis.models.RedisCache.DefinitionStages.WithSku toCreate =
+ RedisManagerFactory.create(config.getSubscription().getId()).redisCaches().define(config.getName())
+ .withRegion(config.getRegion().getName())
+ .withExistingResourceGroup(config.getResourceGroup().getName());
+ com.azure.resourcemanager.redis.models.RedisCache.DefinitionStages.WithCreate withCreate = null;
+ if (config.getPricingTier().isBasic()) {
+ withCreate = toCreate.withBasicSku(config.getPricingTier().getSize());
+ } else if (config.getPricingTier().isStandard()) {
+ withCreate = toCreate.withStandardSku(config.getPricingTier().getSize());
+ } else if (config.getPricingTier().isPremium()) {
+ withCreate = toCreate.withPremiumSku(config.getPricingTier().getSize());
+ }
+ if (config.isEnableNonSslPort()) {
+ withCreate = withCreate.withNonSslPort();
+ }
+ final com.azure.resourcemanager.redis.models.RedisCache redisCache = withCreate.create();
+ return new RedisCache(redisCache.manager(), redisCache);
+ }
+
+ public AzureOperationEvent.Source getEventSource() {
+ return new AzureOperationEvent.Source() {};
+ }
+ }
+
+ @Override
+ public String name() {
+ return "Microsoft.Cache/redis";
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/PricingTier.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/PricingTier.java
new file mode 100644
index 0000000000..20c156e3f7
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/PricingTier.java
@@ -0,0 +1,83 @@
+/*
+ * 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.toolkit.redis;
+
+import com.google.common.collect.ImmutableList;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class PricingTier {
+ private static final String BASIC = "Basic";
+ private static final String STANDARD = "Standard";
+ private static final String PREMIUM = "Premium";
+ private String family;
+ private String capacity;
+ private String memory;
+ private boolean replication;
+
+ public static final PricingTier BASIC_C0 = new PricingTier(BASIC, "C0", "250MB", false);
+ public static final PricingTier BASIC_C1 = new PricingTier(BASIC, "C1", "1GB", false);
+ public static final PricingTier BASIC_C2 = new PricingTier(BASIC, "C2", "2.5GB", false);
+ public static final PricingTier BASIC_C3 = new PricingTier(BASIC, "C3", "6GB", false);
+ public static final PricingTier BASIC_C4 = new PricingTier(BASIC, "C4", "13GB", false);
+ public static final PricingTier BASIC_C5 = new PricingTier(BASIC, "C5", "26GB", false);
+ public static final PricingTier BASIC_C6 = new PricingTier(BASIC, "C6", "53GB", false);
+
+ public static final PricingTier STANDARD_C0 = new PricingTier(STANDARD, "C0", "250MB", true);
+ public static final PricingTier STANDARD_C1 = new PricingTier(STANDARD, "C1", "1GB", true);
+ public static final PricingTier STANDARD_C2 = new PricingTier(STANDARD, "C2", "2.5GB", true);
+ public static final PricingTier STANDARD_C3 = new PricingTier(STANDARD, "C3", "6GB", true);
+ public static final PricingTier STANDARD_C4 = new PricingTier(STANDARD, "C4", "13GB", true);
+ public static final PricingTier STANDARD_C5 = new PricingTier(STANDARD, "C5", "26GB", true);
+ public static final PricingTier STANDARD_C6 = new PricingTier(STANDARD, "C6", "53GB", true);
+
+ public static final PricingTier PREMIUM_C1 = new PricingTier(PREMIUM, "C1", "6GB", true);
+ public static final PricingTier PREMIUM_C2 = new PricingTier(PREMIUM, "C2", "13GB", true);
+ public static final PricingTier PREMIUM_C3 = new PricingTier(PREMIUM, "C3", "26GB", true);
+ public static final PricingTier PREMIUM_C4 = new PricingTier(PREMIUM, "C4", "53GB", true);
+ public static final PricingTier PREMIUM_C5 = new PricingTier(PREMIUM, "C5", "120GB", true);
+
+ public boolean isBasic() {
+ return StringUtils.equals(family, BASIC);
+ }
+
+ public boolean isStandard() {
+ return StringUtils.equals(family, STANDARD);
+ }
+
+ public boolean isPremium() {
+ return StringUtils.equals(family, PREMIUM);
+ }
+
+ public int getSize() {
+ return Integer.parseInt(this.capacity.substring(1));
+ }
+
+ private static final List values = new ImmutableList.Builder().add(
+ BASIC_C0, BASIC_C1, BASIC_C2, BASIC_C3, BASIC_C4, BASIC_C5, BASIC_C6,
+ STANDARD_C0, STANDARD_C1, STANDARD_C2, STANDARD_C3, STANDARD_C4, STANDARD_C5, STANDARD_C6,
+ PREMIUM_C1, PREMIUM_C2, PREMIUM_C3, PREMIUM_C4
+ ).build();
+
+ public static List values() {
+ return values;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s %s (%s)", family, capacity, replication ? (memory + ", Replication") : memory);
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCache.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCache.java
new file mode 100644
index 0000000000..8744697d0a
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCache.java
@@ -0,0 +1,50 @@
+/*
+ * 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.toolkit.redis;
+
+import com.azure.core.management.exception.ManagementException;
+import com.azure.resourcemanager.redis.RedisManager;
+import com.microsoft.azure.toolkit.lib.common.entity.AbstractAzureResource;
+import com.microsoft.azure.toolkit.lib.common.entity.IAzureResource;
+import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
+import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
+import org.apache.http.HttpStatus;
+import org.jetbrains.annotations.Nullable;
+
+import javax.annotation.Nonnull;
+
+public class RedisCache extends AbstractAzureResource
+ implements AzureOperationEvent.Source, IAzureResource {
+
+ @Nonnull
+ private final RedisManager manager;
+
+ public RedisCache(RedisManager manager, com.azure.resourcemanager.redis.models.RedisCache redis) {
+ super(new RedisCacheEntity(redis));
+ this.manager = manager;
+ }
+
+ @AzureOperation(name = "redis.delete", params = {"this.name()"}, type = AzureOperation.Type.SERVICE)
+ public void delete() {
+ manager.redisCaches().deleteById(this.id());
+ refresh();
+ }
+
+ @Nullable
+ @Override
+ protected com.azure.resourcemanager.redis.models.RedisCache loadRemote() {
+ try {
+ this.entity().setRemote(manager.redisCaches().getById(this.entity.getId()));
+ } catch (ManagementException ex) {
+ if (HttpStatus.SC_NOT_FOUND == ex.getResponse().getStatusCode()) {
+ return null;
+ } else {
+ throw ex;
+ }
+ }
+ return entity.getRemote();
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCacheEntity.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCacheEntity.java
new file mode 100644
index 0000000000..8da6a6c6cb
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisCacheEntity.java
@@ -0,0 +1,80 @@
+/*
+ * 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.toolkit.redis;
+
+import com.azure.resourcemanager.redis.models.RedisCache;
+import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
+import com.azure.resourcemanager.resources.fluentcore.arm.models.Resource;
+import com.microsoft.azure.toolkit.lib.common.entity.AbstractAzureResource;
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+
+import javax.annotation.Nonnull;
+import java.util.Optional;
+
+public class RedisCacheEntity extends AbstractAzureResource.RemoteAwareResourceEntity {
+
+ @Nonnull
+ private final ResourceId resourceId;
+
+ public RedisCacheEntity(com.azure.resourcemanager.redis.models.RedisCache redis) {
+ this.resourceId = ResourceId.fromString(redis.id());
+ this.remote = redis;
+ }
+
+ @Override
+ public String getSubscriptionId() {
+ return resourceId.subscriptionId();
+ }
+
+ public String getId() {
+ return resourceId.id();
+ }
+
+ @Override
+ public String getName() {
+ return resourceId.name();
+ }
+
+ public String getResourceGroupName() {
+ return resourceId.resourceGroupName();
+ }
+
+ public Region getRegion() {
+ return remoteOptional().map(remote -> Region.fromName(remote.regionName())).orElse(null);
+ }
+
+ public String getType() {
+ return remoteOptional().map(Resource::type).orElse(null);
+ }
+
+ public int getSSLPort() {
+ return remoteOptional().map(RedisCache::sslPort).orElse(-1);
+ }
+
+ public boolean getNonSslPortEnabled() {
+ return remoteOptional().map(RedisCache::nonSslPort).orElse(false);
+ }
+
+ public String getRedisVersion() {
+ return remoteOptional().map(RedisCache::redisVersion).orElse(null);
+ }
+
+ public String getPrimaryKey() {
+ return remoteOptional().map(remote -> remote.keys().primaryKey()).orElse(null);
+ }
+
+ public String getSecondaryKey() {
+ return remoteOptional().map(remote -> remote.keys().secondaryKey()).orElse(null);
+ }
+
+ public String getHostName() {
+ return remoteOptional().map(RedisCache::hostname).orElse(null);
+ }
+
+ private Optional remoteOptional() {
+ return Optional.ofNullable(this.remote);
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisConfig.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisConfig.java
new file mode 100644
index 0000000000..796a0a2fab
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisConfig.java
@@ -0,0 +1,27 @@
+/*
+ * 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.toolkit.redis;
+
+
+import com.microsoft.azure.toolkit.lib.common.model.Region;
+import com.microsoft.azure.toolkit.lib.common.model.ResourceGroup;
+import com.microsoft.azure.toolkit.lib.common.model.Subscription;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class RedisConfig {
+ private String name;
+ private String id;
+ private ResourceGroup resourceGroup;
+ private Subscription subscription;
+ private Region region;
+ private PricingTier pricingTier;
+ private boolean enableNonSslPort;
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisManagerFactory.java b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisManagerFactory.java
new file mode 100644
index 0000000000..2cbe3b447b
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/java/com/microsoft/azure/toolkit/redis/RedisManagerFactory.java
@@ -0,0 +1,47 @@
+/*
+ * 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.toolkit.redis;
+
+import com.azure.core.http.policy.HttpLogDetailLevel;
+import com.azure.core.http.policy.HttpPipelinePolicy;
+import com.azure.core.management.profile.AzureProfile;
+import com.azure.resourcemanager.redis.RedisManager;
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.AzureConfiguration;
+import com.microsoft.azure.toolkit.lib.AzureService;
+import com.microsoft.azure.toolkit.lib.auth.Account;
+import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
+import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
+
+import java.util.Optional;
+
+public final class RedisManagerFactory {
+
+ private RedisManagerFactory() {
+ }
+
+ @Cacheable(cacheName = "RedisManager", key = "$subscriptionId")
+ public static RedisManager create(String subscriptionId) {
+ final Account account = Azure.az(AzureAccount.class).account();
+ final AzureConfiguration config = Azure.az().config();
+ final String userAgent = config.getUserAgent();
+ final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
+ final AzureProfile azureProfile = new AzureProfile(null, subscriptionId, account.getEnvironment());
+ return RedisManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
+ .withLogLevel(logLevel)
+ .withPolicy(getUserAgentPolicy(userAgent))
+ .authenticate(account.getTokenCredential(subscriptionId), azureProfile);
+ }
+
+ private static HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
+ return (httpPipelineCallContext, httpPipelineNextPolicy) -> {
+ final String previousUserAgent = httpPipelineCallContext.getHttpRequest().getHeaders().getValue("User-Agent");
+ httpPipelineCallContext.getHttpRequest().setHeader("User-Agent", String.format("%s %s", userAgent, previousUserAgent));
+ return httpPipelineNextPolicy.process();
+ };
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/META-INF/services/com.microsoft.azure.toolkit.lib.AzureService b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/META-INF/services/com.microsoft.azure.toolkit.lib.AzureService
new file mode 100644
index 0000000000..eefbfb0023
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/META-INF/services/com.microsoft.azure.toolkit.lib.AzureService
@@ -0,0 +1 @@
+com.microsoft.azure.toolkit.redis.AzureRedis
diff --git a/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/redis.properties b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/redis.properties
new file mode 100644
index 0000000000..72d04c000f
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-redis-lib/src/main/resources/com/microsoft/azure/toolkit/operation/title/base/redis.properties
@@ -0,0 +1,5 @@
+redis.create=create redis cache({0})
+redis.delete=delete redis cache({0})
+redis.list.subscription|selected=list Redis Caches of selected subscriptions
+redis.check_name=check name availability for redis cahe({0})
+redis.get.id=get Redis cache({0})
\ No newline at end of file
diff --git a/azure-toolkit-libs/azure-toolkit-resource-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-resource-lib/pom.xml
index 62aca0d1e5..36ff86a00a 100644
--- a/azure-toolkit-libs/azure-toolkit-resource-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-resource-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
diff --git a/azure-toolkit-libs/azure-toolkit-resource-lib/src/main/java/com/microsoft/azure/toolkit/lib/resource/AzureGroup.java b/azure-toolkit-libs/azure-toolkit-resource-lib/src/main/java/com/microsoft/azure/toolkit/lib/resource/AzureGroup.java
index d8b5ceb6d1..f65d6999ee 100644
--- a/azure-toolkit-libs/azure-toolkit-resource-lib/src/main/java/com/microsoft/azure/toolkit/lib/resource/AzureGroup.java
+++ b/azure-toolkit-libs/azure-toolkit-resource-lib/src/main/java/com/microsoft/azure/toolkit/lib/resource/AzureGroup.java
@@ -5,17 +5,9 @@
package com.microsoft.azure.toolkit.lib.resource;
-import com.azure.core.http.policy.HttpLogDetailLevel;
-import com.azure.core.http.policy.HttpPipelinePolicy;
-import com.azure.core.management.profile.AzureProfile;
-import com.azure.resourcemanager.resources.ResourceManager;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
-import com.microsoft.azure.toolkit.lib.Azure;
-import com.microsoft.azure.toolkit.lib.AzureConfiguration;
import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.SubscriptionScoped;
-import com.microsoft.azure.toolkit.lib.auth.Account;
-import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
import com.microsoft.azure.toolkit.lib.common.cache.Preload;
import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
@@ -96,27 +88,4 @@ private static ResourceGroup fromResource(@Nonnull com.azure.resourcemanager.res
String id = resource.id();
return ResourceGroup.builder().subscriptionId(subscriptionId).id(id).name(name).region(region).build();
}
-
- @Cacheable(cacheName = "resource/{}/manager", key = "$subscriptionId")
- private ResourceManager getResourceManager(String subscriptionId) {
- final Account account = Azure.az(AzureAccount.class).account();
- final AzureConfiguration config = Azure.az().config();
- final String userAgent = config.getUserAgent();
- final HttpLogDetailLevel logDetailLevel = config.getLogLevel() == null ?
- HttpLogDetailLevel.NONE : HttpLogDetailLevel.valueOf(config.getLogLevel());
- final AzureProfile azureProfile = new AzureProfile(account.getEnvironment());
- return ResourceManager.configure()
- .withLogLevel(logDetailLevel)
- .withPolicy(getUserAgentPolicy(userAgent)) // set user agent with policy
- .authenticate(account.getTokenCredential(subscriptionId), azureProfile)
- .withSubscription(subscriptionId);
- }
-
- private HttpPipelinePolicy getUserAgentPolicy(String userAgent) {
- return (httpPipelineCallContext, httpPipelineNextPolicy) -> {
- final String previousUserAgent = httpPipelineCallContext.getHttpRequest().getHeaders().getValue("User-Agent");
- httpPipelineCallContext.getHttpRequest().setHeader("User-Agent", String.format("%s %s", userAgent, previousUserAgent));
- return httpPipelineNextPolicy.process();
- };
- }
}
diff --git a/azure-toolkit-libs/azure-toolkit-springcloud-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-springcloud-lib/pom.xml
index 00a3ba103d..e3308f61e0 100644
--- a/azure-toolkit-libs/azure-toolkit-springcloud-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-springcloud-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
diff --git a/azure-toolkit-libs/azure-toolkit-springcloud-lib/src/main/java/com/microsoft/azure/toolkit/lib/springcloud/AzureSpringCloud.java b/azure-toolkit-libs/azure-toolkit-springcloud-lib/src/main/java/com/microsoft/azure/toolkit/lib/springcloud/AzureSpringCloud.java
index 8c76356444..5bc8f95c04 100644
--- a/azure-toolkit-libs/azure-toolkit-springcloud-lib/src/main/java/com/microsoft/azure/toolkit/lib/springcloud/AzureSpringCloud.java
+++ b/azure-toolkit-libs/azure-toolkit-springcloud-lib/src/main/java/com/microsoft/azure/toolkit/lib/springcloud/AzureSpringCloud.java
@@ -18,6 +18,8 @@
import com.microsoft.azure.toolkit.lib.SubscriptionScoped;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
+import com.microsoft.azure.toolkit.lib.common.cache.CacheEvict;
+import com.microsoft.azure.toolkit.lib.common.cache.CacheManager;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
import com.microsoft.azure.toolkit.lib.common.cache.Preload;
import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
@@ -32,6 +34,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@Slf4j
@@ -68,16 +71,16 @@ private SpringCloudCluster cluster(@Nonnull SpringCloudClusterEntity cluster) {
@Nonnull
@Preload
@AzureOperation(name = "springcloud|cluster.list.subscription|selected", type = AzureOperation.Type.SERVICE)
- public List clusters(boolean... force) {
+ public List clusters() {
return this.getSubscriptions().stream().parallel()
- .flatMap(s -> clusters(s.getId(), force).stream())
+ .flatMap(s -> clusters(s.getId()).stream())
.collect(Collectors.toList());
}
@Nonnull
- @Cacheable(cacheName = "asc/{}/clusters", key = "$subscriptionId", condition = "!(force&&force[0])")
+ @Cacheable(cacheName = "asc/{}/clusters", key = "$subscriptionId")
@AzureOperation(name = "springcloud|cluster.list.subscription", params = "subscriptionId", type = AzureOperation.Type.SERVICE)
- private List clusters(@Nonnull String subscriptionId, boolean... force) {
+ private List clusters(@Nonnull String subscriptionId) {
try {
return getClient(subscriptionId).list().stream()
.map(this::cluster)
@@ -93,7 +96,11 @@ private List clusters(@Nonnull String subscriptionId, boolea
@AzureOperation(name = "common|service.refresh", params = "this.name()", type = AzureOperation.Type.SERVICE)
public void refresh() {
- this.clusters(true);
+ try {
+ CacheManager.evictCache("asc/{}/clusters", CacheEvict.ALL);
+ } catch (ExecutionException e) {
+ log.warn("failed to evict cache", e);
+ }
}
@Override
@@ -110,6 +117,7 @@ protected SpringServices getClient(final String subscriptionId) {
final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
final AzureProfile azureProfile = new AzureProfile(null, subscriptionId, account.getEnvironment());
return AppPlatformManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogLevel(logLevel)
.withPolicy(getUserAgentPolicy(userAgent)) // set user agent with policy
.authenticate(account.getTokenCredential(subscriptionId), azureProfile)
diff --git a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/pom.xml
index 4a144c0e97..4f60210563 100644
--- a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
diff --git a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/AzureSqlServer.java b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/AzureSqlServer.java
index 545a4623b3..73321cd859 100644
--- a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/AzureSqlServer.java
+++ b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/AzureSqlServer.java
@@ -4,7 +4,6 @@
*/
package com.microsoft.azure.toolkit.lib.sqlserver;
-import com.azure.core.management.Region;
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.azure.resourcemanager.sql.SqlServerManager;
import com.azure.resourcemanager.sql.models.CapabilityStatus;
@@ -69,7 +68,7 @@ public CheckNameAvailabilityResultEntity checkNameAvailability(String subscripti
public boolean checkRegionCapability(String subscriptionId, String region) {
SqlServerManager manager = SqlServerManagerFactory.create(subscriptionId);
- com.azure.resourcemanager.sql.models.RegionCapabilities capabilities = manager.sqlServers().getCapabilitiesByRegion(Region.fromName(region));
+ com.azure.resourcemanager.sql.models.RegionCapabilities capabilities = manager.sqlServers().getCapabilitiesByRegion(com.azure.core.management.Region.fromName(region));
return Objects.nonNull(capabilities.status()) && CapabilityStatus.AVAILABLE == capabilities.status();
}
@@ -116,4 +115,7 @@ public AzureOperationEvent.Source getEventSource() {
}
}
+ public String name() {
+ return "Microsoft.SQL/servers";
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/SqlServerManagerFactory.java b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/SqlServerManagerFactory.java
index e4c219e915..322f6041df 100644
--- a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/SqlServerManagerFactory.java
+++ b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/SqlServerManagerFactory.java
@@ -1,3 +1,8 @@
+/*
+ * 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.toolkit.lib.sqlserver;
import com.azure.core.http.policy.HttpLogDetailLevel;
@@ -6,6 +11,7 @@
import com.azure.resourcemanager.sql.SqlServerManager;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureConfiguration;
+import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
@@ -25,6 +31,7 @@ public static SqlServerManager create(String subscriptionId) {
final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
final AzureProfile azureProfile = new AzureProfile(null, subscriptionId, account.getEnvironment());
return SqlServerManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogLevel(logLevel)
.withPolicy(getUserAgentPolicy(userAgent))
.authenticate(account.getTokenCredential(subscriptionId), azureProfile);
diff --git a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/model/SqlServerEntity.java b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/model/SqlServerEntity.java
index aec5e6bc09..88098f3948 100644
--- a/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/model/SqlServerEntity.java
+++ b/azure-toolkit-libs/azure-toolkit-sqlserver-lib/src/main/java/com/microsoft/azure/toolkit/lib/sqlserver/model/SqlServerEntity.java
@@ -75,6 +75,11 @@ public String getState() {
return remoteOptional().map(SqlServer::state).orElse(null);
}
+ @Override
+ public String getVersion() {
+ return remoteOptional().map(SqlServer::version).orElse(null);
+ }
+
private Optional remoteOptional() {
return Optional.ofNullable(this.remote);
}
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/pom.xml b/azure-toolkit-libs/azure-toolkit-storage-lib/pom.xml
index 3e341398c5..2d10f5b927 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/pom.xml
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/pom.xml
@@ -5,7 +5,7 @@
azure-toolkit-libs
com.microsoft.azure
- 0.11.0
+ 0.12.1
4.0.0
@@ -114,4 +114,4 @@
-
\ No newline at end of file
+
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/StorageManagerFactory.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/StorageManagerFactory.java
index 6af5ffab41..7cb3e6a370 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/StorageManagerFactory.java
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/StorageManagerFactory.java
@@ -11,6 +11,7 @@
import com.azure.resourcemanager.storage.StorageManager;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureConfiguration;
+import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.auth.Account;
import com.microsoft.azure.toolkit.lib.auth.AzureAccount;
import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
@@ -30,6 +31,7 @@ public static StorageManager create(String subscriptionId) {
final HttpLogDetailLevel logLevel = Optional.ofNullable(config.getLogLevel()).map(HttpLogDetailLevel::valueOf).orElse(HttpLogDetailLevel.NONE);
final AzureProfile azureProfile = new AzureProfile(null, subscriptionId, account.getEnvironment());
return StorageManager.configure()
+ .withHttpClient(AzureService.getDefaultHttpClient())
.withLogLevel(logLevel)
.withPolicy(getUserAgentPolicy(userAgent))
.authenticate(account.getTokenCredential(subscriptionId), azureProfile);
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/AccessTier.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/AccessTier.java
new file mode 100644
index 0000000000..bf7e891667
--- /dev/null
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/AccessTier.java
@@ -0,0 +1,20 @@
+/*
+ * 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.toolkit.lib.storage.model;
+
+public enum AccessTier {
+ HOT("Hot"),
+ COOL("Cool");
+ private final String value;
+
+ AccessTier(String value) {
+ this.value = value;
+ }
+
+ public String toString() {
+ return this.value;
+ }
+}
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/Kind.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/Kind.java
index 5f7c2ad015..c3ea408d87 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/Kind.java
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/Kind.java
@@ -25,7 +25,8 @@ public class Kind implements ExpandableParameter {
public static final Kind FILE_STORAGE = new Kind(Performance.PREMIUM, "FileStorage", "File Storage");
public static final Kind PAGE_BLOB_STORAGE = new Kind(Performance.PREMIUM, "StorageV2", "Page Blobs Storage");
- private static final List values = new ImmutableList.Builder().add(STORAGE, STORAGE_V2, BLOCK_BLOB_STORAGE, FILE_STORAGE, PAGE_BLOB_STORAGE).build();
+ private static final List values = new ImmutableList.Builder().add(STORAGE, STORAGE_V2,
+ BLOCK_BLOB_STORAGE, FILE_STORAGE, PAGE_BLOB_STORAGE).build();
private final Performance performance;
private final String name;
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/StorageAccountConfig.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/StorageAccountConfig.java
index 31524a64da..2099268b2d 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/StorageAccountConfig.java
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/model/StorageAccountConfig.java
@@ -9,6 +9,7 @@
import com.microsoft.azure.toolkit.lib.common.model.ResourceGroup;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
import lombok.Builder;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -17,6 +18,7 @@
@Getter
@Setter
@Builder
+@EqualsAndHashCode
public class StorageAccountConfig implements IStorageAccountEntity {
private String name;
@@ -28,6 +30,7 @@ public class StorageAccountConfig implements IStorageAccountEntity {
private Performance performance;
private Kind kind;
private Redundancy redundancy;
+ private AccessTier accessTier;
@Override
public String getSubscriptionId() {
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/AzureStorageAccount.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/AzureStorageAccount.java
index d87d6aefd0..c11b29230d 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/AzureStorageAccount.java
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/AzureStorageAccount.java
@@ -5,15 +5,19 @@
package com.microsoft.azure.toolkit.lib.storage.service;
-
import com.azure.resourcemanager.resources.fluentcore.arm.ResourceId;
import com.azure.resourcemanager.storage.StorageManager;
+import com.azure.resourcemanager.storage.models.AccessTier;
import com.azure.resourcemanager.storage.models.CheckNameAvailabilityResult;
import com.azure.resourcemanager.storage.models.Reason;
import com.azure.resourcemanager.storage.models.SkuName;
import com.azure.resourcemanager.storage.models.StorageAccountSkuType;
+import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.AzureService;
import com.microsoft.azure.toolkit.lib.SubscriptionScoped;
+import com.microsoft.azure.toolkit.lib.common.cache.CacheEvict;
+import com.microsoft.azure.toolkit.lib.common.cache.CacheManager;
+import com.microsoft.azure.toolkit.lib.common.cache.Cacheable;
import com.microsoft.azure.toolkit.lib.common.entity.CheckNameAvailabilityResultEntity;
import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
import com.microsoft.azure.toolkit.lib.common.model.Subscription;
@@ -24,15 +28,20 @@
import com.microsoft.azure.toolkit.lib.storage.model.Performance;
import com.microsoft.azure.toolkit.lib.storage.model.Redundancy;
import com.microsoft.azure.toolkit.lib.storage.model.StorageAccountConfig;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
-public class AzureStorageAccount extends SubscriptionScoped implements AzureService {
+@Slf4j
+public class AzureStorageAccount extends SubscriptionScoped
+ implements AzureService, AzureOperationEvent.Source {
public AzureStorageAccount() {
super(AzureStorageAccount::new);
@@ -44,22 +53,27 @@ private AzureStorageAccount(@Nonnull final List subscriptions) {
public List list() {
return getSubscriptions().stream()
- .map(subscription -> StorageManagerFactory.create(subscription.getId()))
- .flatMap(manager -> manager.storageAccounts().list().stream())
- .map(account -> new StorageAccount(account.manager(), account))
+ .flatMap(s -> list(s.getId()).stream())
+ .collect(Collectors.toList());
+ }
+
+ @Cacheable(cacheName = "storage/{}/accounts", key = "$sid")
+ public List list(String sid) {
+ return StorageManagerFactory.create(sid).storageAccounts().list().stream()
+ .map(StorageAccount::new)
.collect(Collectors.toList());
}
public StorageAccount get(@Nonnull String id) {
final com.azure.resourcemanager.storage.models.StorageAccount account =
StorageManagerFactory.create(ResourceId.fromString(id).subscriptionId()).storageAccounts().getById(id);
- return new StorageAccount(account.manager(), account);
+ return new StorageAccount(account);
}
public StorageAccount get(@Nonnull final String resourceGroup, @Nonnull final String name) {
final com.azure.resourcemanager.storage.models.StorageAccount account =
StorageManagerFactory.create(getDefaultSubscription().getId()).storageAccounts().getByResourceGroup(resourceGroup, name);
- return new StorageAccount(account.manager(), account);
+ return new StorageAccount(account);
}
public CheckNameAvailabilityResultEntity checkNameAvailability(String subscriptionId, String name) {
@@ -84,17 +98,23 @@ public List listSupportedRedundancies(@Nonnull Performance performan
.collect(Collectors.toList());
}
+ @AzureOperation(name = "common|service.refresh", params = "this.name()", type = AzureOperation.Type.SERVICE)
+ public void refresh() {
+ try {
+ CacheManager.evictCache("storage/{}/accounts", CacheEvict.ALL);
+ } catch (ExecutionException e) {
+ log.warn("failed to evict cache", e);
+ }
+ }
+
public Creator create(StorageAccountConfig config) {
return new Creator(config);
}
- public class Creator implements ICommittable, AzureOperationEvent.Source {
+ @RequiredArgsConstructor
+ public static class Creator implements ICommittable, AzureOperationEvent.Source {
- private StorageAccountConfig config;
-
- Creator(StorageAccountConfig config) {
- this.config = config;
- }
+ private final StorageAccountConfig config;
@Override
@AzureOperation(name = "storage|account.create", params = {"this.config.getName()"}, type = AzureOperation.Type.SERVICE)
@@ -111,16 +131,25 @@ public StorageAccount commit() {
withCreate = withCreate.withFileStorageAccountKind();
} else if (Objects.equals(Kind.BLOCK_BLOB_STORAGE, config.getKind())) {
withCreate = withCreate.withBlockBlobStorageAccountKind();
+ } else if (Objects.equals(Kind.BLOB_STORAGE, config.getKind())) {
+ withCreate = withCreate.withBlobStorageAccountKind().withAccessTier(
+ Optional.ofNullable(config.getAccessTier()).map(t -> AccessTier.fromString(t.toString())).orElse(null));
} else {
withCreate = withCreate.withGeneralPurposeAccountKindV2();
}
com.azure.resourcemanager.storage.models.StorageAccount account = withCreate.create();
- return new StorageAccount(account.manager(), account);
+ Azure.az(AzureStorageAccount.class).refresh();
+ return new StorageAccount(account);
}
+ @Nonnull
public AzureOperationEvent.Source getEventSource() {
- return new AzureOperationEvent.Source() {};
+ return new AzureOperationEvent.Source() {
+ };
}
}
+ public String name() {
+ return "Microsoft.Storage/storageAccounts";
+ }
}
diff --git a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/StorageAccount.java b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/StorageAccount.java
index f3c0c71ea0..ed720e2de5 100644
--- a/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/StorageAccount.java
+++ b/azure-toolkit-libs/azure-toolkit-storage-lib/src/main/java/com/microsoft/azure/toolkit/lib/storage/service/StorageAccount.java
@@ -5,25 +5,31 @@
package com.microsoft.azure.toolkit.lib.storage.service;
+import com.azure.core.management.AzureEnvironment;
import com.azure.core.management.exception.ManagementException;
+import com.azure.resourcemanager.resources.fluentcore.utils.ResourceManagerUtils;
import com.azure.resourcemanager.storage.StorageManager;
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.auth.AzureCloud;
import com.microsoft.azure.toolkit.lib.common.entity.AbstractAzureResource;
import com.microsoft.azure.toolkit.lib.common.entity.IAzureResource;
+import com.microsoft.azure.toolkit.lib.common.entity.Removable;
import com.microsoft.azure.toolkit.lib.common.event.AzureOperationEvent;
import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
import com.microsoft.azure.toolkit.lib.storage.model.StorageAccountEntity;
import org.apache.http.HttpStatus;
import javax.annotation.Nonnull;
+import java.util.Objects;
public class StorageAccount extends AbstractAzureResource
- implements AzureOperationEvent.Source, IAzureResource {
+ implements Removable, AzureOperationEvent.Source, IAzureResource {
@Nonnull
private final StorageManager manager;
- public StorageAccount(@Nonnull StorageManager manager, @Nonnull com.azure.resourcemanager.storage.models.StorageAccount server) {
+ public StorageAccount(@Nonnull com.azure.resourcemanager.storage.models.StorageAccount server) {
super(new StorageAccountEntity(server));
- this.manager = manager;
+ this.manager = server.manager();
}
@Override
@@ -42,6 +48,27 @@ protected com.azure.resourcemanager.storage.models.StorageAccount loadRemote() {
@AzureOperation(name = "storage|account.delete", params = {"this.entity().getName()"}, type = AzureOperation.Type.SERVICE)
public void delete() {
- manager.storageAccounts().deleteById(this.entity.getId());
+ if (this.exists()) {
+ this.status(Status.PENDING);
+ manager.storageAccounts().deleteById(this.entity.getId());
+ Azure.az(AzureStorageAccount.class).refresh();
+ }
+ }
+
+ @AzureOperation(name = "storage|account.get_connection_string", params = {"this.entity().getName()"}, type = AzureOperation.Type.SERVICE)
+ public String getConnectionString() {
+ // see https://github.com/Azure/azure-cli/blob/ac3b190d4d/src/azure-cli/azure/cli/command_modules/storage/operations/account.py#L232
+ final AzureEnvironment environment = Azure.az(AzureCloud.class).get();
+ return ResourceManagerUtils.getStorageConnectionString(this.name(), getKey(), environment);
+ }
+
+ @AzureOperation(name = "storage|account.get_key", params = {"this.entity().getName()"}, type = AzureOperation.Type.SERVICE)
+ public String getKey() {
+ return Objects.requireNonNull(this.remote()).getKeys().get(0).keyName();
+ }
+
+ @Override
+ public void remove() {
+ this.delete();
}
}
diff --git a/azure-toolkit-libs/pom.xml b/azure-toolkit-libs/pom.xml
index 8e3f287b4b..3b5e7801ef 100644
--- a/azure-toolkit-libs/pom.xml
+++ b/azure-toolkit-libs/pom.xml
@@ -5,7 +5,7 @@
4.0.0
com.microsoft.azure
azure-toolkit-libs
- 0.11.0
+ 0.12.1
pom
Libs for Azure Toolkits
Wrapped libs for Microsoft Azure Toolkits
@@ -45,6 +45,8 @@
azure-toolkit-applicationinsights-lib
azure-toolkit-storage-lib
azure-toolkit-database-lib
+ azure-toolkit-redis-lib
+ azure-toolkit-compute-lib
@@ -66,19 +68,15 @@
1.6.7
2.6.3
[2.0,)
- 1.0.0-beta
1.0.0-beta.1
- 1.0.0-beta
1.7.12
1.3.0
2.5.0
8.6.6
1.41.1
3.2.2
- 1.6.2
12.9.1
1.4.2
- 11.0.1
4.2.8
4.2.8
4.1.8
@@ -87,7 +85,7 @@
12.11.1
12.9.1
12.5.1
-
+ 1.9.2
1.9.7.M3
3.3.0
1.15
@@ -100,17 +98,15 @@
1.21
2.7
2.1.3
- 2.7.1
2.8.7
30.1.1-jre
4.5.13
- 4.9.1
2.12.3
0.8.7
2.3.2
21.0.1
2.2.14
- 2.5.11
+ 3.0.9
4.13.2
1.18.20
3.10.0
@@ -122,15 +118,16 @@
1.1.1
0.9.1
0.9.12
+ 1.0.6
1.9.2
- 9.7
+ 9.15
3.1.0
9.9.3
2.10.10
4.4.14
1.2.2
3.0.2-b01
- 3.0.2-b01
+ 3.0.2
3.0.1
5.87.0.RELEASE
0.9.0
@@ -140,6 +137,7 @@
2.0.9
1.0.0
1.0.57
+ 2.7.0
@@ -161,6 +159,11 @@
azure-toolkit-common-lib
${azure.toolkit-lib.version}
+
+ com.azure
+ azure-core-http-netty
+ ${azure.core.http.netty.version}
+
com.microsoft.azure
azure-toolkit-auth-lib
@@ -206,18 +209,17 @@
azure-toolkit-storage-lib
${azure.toolkit-lib.version}
-
com.microsoft.azure
- azure
- ${azure.version}
-
-
- javax.xml.bind
- jaxb-api
-
-
+ azure-toolkit-redis-lib
+ ${azure.toolkit-lib.version}
+
+ com.microsoft.azure
+ azure-toolkit-compute-lib
+ ${azure.toolkit-lib.version}
+
+
com.microsoft.azure
azure-annotations
@@ -238,11 +240,6 @@
azure-client-authentication
${azure.client.version}
-
- com.microsoft.azure
- azure-mgmt-storage
- ${azure.version}
-
com.microsoft.azure
applicationinsights-core
@@ -303,21 +300,11 @@
azure-security-keyvault-certificates
${azure.security.keyvault.certificates.version}
-
- com.microsoft.azure.appplatform.v2020_07_01
- azure-mgmt-appplatform
- ${azure.azure-mgmt-appplatform.version}
-
com.azure
azure-core-http-netty
${azure.core-http-netty.version}
-
- com.microsoft.azure
- azure-mgmt-resources
- ${azure.version}
-
com.nimbusds
oauth2-oidc-sdk
@@ -512,7 +499,7 @@
com.azure.resourcemanager
- azure-resourcemanager
+ azure-resourcemanager-appservice
${azure.resourcemanager.version}
@@ -535,11 +522,21 @@
azure-resourcemanager-mysql
${azure-resourcemanager-mysql.version}
+
+ com.azure.resourcemanager
+ azure-resourcemanager-redis
+ ${azure-resourcemanager-redis.version}
+
com.azure.resourcemanager
azure-resourcemanager-appplatform
${azure.resourcemanager.version}
+
+ com.azure.resourcemanager
+ azure-resourcemanager-compute
+ ${azure.resourcemanager.version}
+
com.azure
azure-identity
@@ -571,30 +568,10 @@
com.azure
- azure-core-http-netty
+ azure-core-http-okhttp
-
- com.azure
- azure-core-http-okhttp
- ${azure.core.http.okhttp.version}
-
-
- com.squareup.okhttp3
- okhttp
- ${okhttp.version}
-
-
- com.squareup.okhttp3
- logging-interceptor
- ${okhttp.version}
-
-
- com.squareup.okhttp3
- okhttp-urlconnection
- ${okhttp.version}
-
org.apache.httpcomponents
httpclient
@@ -662,17 +639,6 @@
httpcore
${httpcore.version}
-
- com.google.errorprone
- error_prone_core
- ${error.prone.core.version}
-
-
- com.google.guava
- guava
-
-
-
com.microsoft.azure
azure-arm-client-runtime
@@ -698,6 +664,11 @@
java-semver
${semver.version}
+
+ io.projectreactor.netty
+ reactor-netty
+ ${reactor.netty.version}
+
jakarta.xml.bind
@@ -713,6 +684,16 @@
com.networknt
json-schema-validator
${networknt.json-schema-validator.version}
+
+
+ com.sun.mail
+ mailapi
+
+
+ org.mozilla
+ rhino
+
+
com.github.java-json-tools
diff --git a/azure-webapp-maven-plugin/CHANGELOG.md b/azure-webapp-maven-plugin/CHANGELOG.md
index 798e874c59..697f6d60ff 100644
--- a/azure-webapp-maven-plugin/CHANGELOG.md
+++ b/azure-webapp-maven-plugin/CHANGELOG.md
@@ -1,6 +1,7 @@
# Change Log
All notable changes to the "Maven Plugin for Azure App Service" will be documented in this file.
- [Change Log](#change-log)
+ - [2.2.0](#210)
- [2.1.0](#210)
- [2.0.0](#200)
- [1.15.0](#1150)
@@ -26,6 +27,14 @@ All notable changes to the "Maven Plugin for Azure App Service" will be document
- [1.1.0](#110)
- [1.0.0](#100)
+## 2.2.0
+- Support default value for region/pricing tier/webContainer/javaVersion [#1755](https://github.com/microsoft/azure-maven-plugins/pull/1755)
+- Support flag to skip create azure resources PR [#1762](https://github.com/microsoft/azure-maven-plugins/pull/1762), Issue [#1651](https://github.com/microsoft/azure-maven-plugins/issues/1651)
+- Support username and password in proxy [#1677](https://github.com/microsoft/azure-maven-plugins/pull/1677)
+- Check whether webapp name is available before creating webapp [#1728](https://github.com/microsoft/azure-maven-plugins/pull/1728)
+- Remove unsupported JBoss 7.2 Runtime(use JBoss 7 instead) [#1751](https://github.com/microsoft/azure-maven-plugins/pull/1751)
+- Fix warning message of `illegal reflective access from groovy` [#1763](https://github.com/microsoft/azure-maven-plugins/pull/1763)
+
## 2.1.0
- Support static validation against json schema [#1647](https://github.com/microsoft/azure-maven-plugins/pull/1647)
- Support custom values for pricingTier/region/webContainer/javaVersion [#1643](https://github.com/microsoft/azure-maven-plugins/pull/1643)
@@ -138,4 +147,3 @@ All notable changes to the "Maven Plugin for Azure App Service" will be document
## 1.0.0
- Add the support for deploying Web App to an existing App Service Plan
-
diff --git a/azure-webapp-maven-plugin/README.md b/azure-webapp-maven-plugin/README.md
index d9bee75d41..385104014a 100644
--- a/azure-webapp-maven-plugin/README.md
+++ b/azure-webapp-maven-plugin/README.md
@@ -25,7 +25,7 @@ Mavan plugins supports Azure Cli and some other auth methods, see [Authenticatio
You can prepare your application for Azure Web App easily with one command:
```shell
-mvn com.microsoft.azure:azure-webapp-maven-plugin:1.14.0:config
+mvn com.microsoft.azure:azure-webapp-maven-plugin:2.2.0:config
```
This command adds a `azure-webapp-maven-plugin` plugin and related configuration by prompting you to select an existing Azure Web App or create a new one. Then you can deploy your Java app to Azure using the following command:
@@ -39,7 +39,7 @@ Here is a typical configuration for Azure Web App Maven Plugin:
com.microsoft.azure
azure-webapp-maven-plugin
- 2.1.0
+ 2.2.0
111111-11111-11111-1111111
spring-boot-xxxxxxxxxx-rg
@@ -72,12 +72,12 @@ Property | Required | Description
`` | false | Specifies the target subscription.
Use this setting when you have multiple subscriptions in your authentication file.|
`` | true | Azure Resource Group for your Web App. |
`` | true | The name of your Web App. |
-``| false | The pricing tier for your Web App. The default value is **P1V2**.|
-``| false | Specifies the region where your Web App will be hosted; the default value is **westeurope**. All valid regions at [Supported Regions](#region) section. |
-``| false | Specifies the os, supported values are *Linux*, *Windows* and *Docker*. |
-``| false | Specifies the runtime stack, values for Linux are: *Tomcat 8.5*, *Tomcat 9.0*, *Java SE*, *JbossEAP 7.2*|
-``| false | Specifies the java version, values are: *Java 8* or *Java 11*|
-``| false | Specifies the target file to be deployed |
+``| false | The pricing tier for your Web App. The default value is **P1V2**(**P1v3** for JBoss).|
+``| false | Specifies the region where your Web App will be hosted; the default value is **centralus**(or the first region if centralus is not available in your subscription). All valid regions at [Supported Regions](#region) section. |
+ ``| false | Specifies the os, supported values are *Linux*, *Windows* and *Docker*. The default value is **linux**|
+``| false | Specifies the runtime stack, values for Linux are: *Tomcat 8.5*, *Tomcat 9.0*, *Java SE*, *JBossEAP 7*, The default value would be **Tomcat 8.5** or **Java SE** or **JBossEAP 7** according to your project type |
+``| false | Specifies the java version, values are: *Java 8* or *Java 11*. The default value is your project compiler level|
+``| false | Specifies the target file to be deployed. If it is not specified, a default webapp is created without any deployments. |
## Feedback and Questions
To report bugs or request new features, file issues on [Issues](https://github.com/microsoft/azure-maven-plugins/issues). Or, ask questions on [Stack Overflow with tag azure-java-tools](https://stackoverflow.com/questions/tagged/azure-java-tools).
diff --git a/azure-webapp-maven-plugin/pom.xml b/azure-webapp-maven-plugin/pom.xml
index 63467a90c2..bcefd09af1 100644
--- a/azure-webapp-maven-plugin/pom.xml
+++ b/azure-webapp-maven-plugin/pom.xml
@@ -7,11 +7,11 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
azure-webapp-maven-plugin
- 2.2.0-SNAPSHOT
+ 2.2.0
maven-plugin
Maven Plugin for Azure Web Apps
Maven Plugin for Azure Web Apps
@@ -215,6 +215,56 @@
+
+
+
+ com.nickwongdev
+ aspectj-maven-plugin
+
+ false
+ 1.8
+ 1.8
+ ignore
+ 1.8
+ UTF-8
+ false
+ true
+ true
+
+
+
+ com.microsoft.azure
+ azure-toolkit-common-lib
+
+
+
+
+
+ compile-with-aspectj
+ process-classes
+
+
+ ${project.build.directory}/classes
+
+
+
+ compile
+
+
+
+ test-compile-with-aspectj
+ process-test-classes
+
+
+ ${project.build.directory}/test-classes
+
+
+
+ test-compile
+
+
+
+
org.apache.maven.plugins
maven-plugin-plugin
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/AbstractWebAppMojo.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/AbstractWebAppMojo.java
index be08a72270..3a1c6328c1 100644
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/AbstractWebAppMojo.java
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/AbstractWebAppMojo.java
@@ -44,11 +44,10 @@ public abstract class AbstractWebAppMojo extends AbstractAppServiceMojo {
public static final String DOCKER_IMAGE_TYPE_KEY = "dockerImageType";
public static final String DEPLOYMENT_TYPE_KEY = "deploymentType";
public static final String OS_KEY = "os";
- public static final String INVALID_CONFIG_KEY = "invalidConfiguration";
public static final String SCHEMA_VERSION_KEY = "schemaVersion";
public static final String DEPLOY_TO_SLOT_KEY = "isDeployToSlot";
- private static final String INVALID_PARAMETER_ERROR_MESSAGE = "Invalid values found in configuration, please correct the value with messages below:";
-
+ public static final String SKIP_CREATE_RESOURCE_KEY = "skipCreateResource";
+ public static final String INVALID_PARAMETER_ERROR_MESSAGE = "Invalid values found in configuration, please correct the value with messages below:";
//region Properties
/**
@@ -89,6 +88,20 @@ public abstract class AbstractWebAppMojo extends AbstractAppServiceMojo {
@Parameter(property = "webapp.skip", defaultValue = "false")
protected boolean skip;
+ /**
+ * TODO(andxu): move this flag to AbstractAzureMojo
+ */
+ @JsonIgnore
+ @Parameter(property = "azure.resource.create.skip", defaultValue = "false")
+ protected boolean skipAzureResourceCreate;
+
+ /**
+ * TODO(andxu): move this flag to AbstractAzureMojo
+ */
+ @JsonIgnore
+ @Parameter(property = "skipCreateAzureResource")
+ protected boolean skipCreateAzureResource;
+
/**
* App Service region, which will only be used to create App Service at the first time.
*/
@@ -136,7 +149,8 @@ public abstract class AbstractWebAppMojo extends AbstractAppServiceMojo {
private boolean isRuntimeInjected = false;
@JsonIgnore
- private WebAppConfig config;
+ @Getter
+ protected ConfigParser configParser = new ConfigParser(this);
//endregion
@@ -226,6 +240,8 @@ public Map getTelemetryProperties() {
final boolean isDeployToSlot = Optional.ofNullable(getDeploymentSlotSetting()).map(DeploymentSlotSetting::getName)
.map(StringUtils::isNotEmpty).orElse(false);
map.put(DEPLOY_TO_SLOT_KEY, String.valueOf(isDeployToSlot));
+
+ map.put(SKIP_CREATE_RESOURCE_KEY, String.valueOf(skipAzureResourceCreate || skipCreateAzureResource));
return map;
}
@@ -238,13 +254,6 @@ protected void validateConfiguration(Consumer validationMessa
}
}
- protected synchronized WebAppConfig getWebAppConfig() throws AzureExecutionException {
- if (config == null) {
- config = new ConfigParser(this).parse();
- }
- return config;
- }
-
@Override
public String getSubscriptionId() {
return appServiceClient == null ? this.subscriptionId : appServiceClient.getDefaultSubscription().getId();
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/ConfigMojo.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/ConfigMojo.java
index 5e914db580..d3a962ad38 100644
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/ConfigMojo.java
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/ConfigMojo.java
@@ -14,15 +14,14 @@
import com.microsoft.azure.maven.webapp.configuration.SchemaVersion;
import com.microsoft.azure.maven.webapp.handlers.WebAppPomHandler;
import com.microsoft.azure.maven.webapp.models.WebAppOption;
-import com.microsoft.azure.maven.webapp.parser.ConfigParser;
import com.microsoft.azure.toolkit.lib.Azure;
import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
+import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
import com.microsoft.azure.toolkit.lib.appservice.model.Runtime;
import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
import com.microsoft.azure.toolkit.lib.appservice.service.IWebApp;
import com.microsoft.azure.toolkit.lib.auth.exception.AzureToolkitAuthenticationException;
import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
@@ -52,11 +51,11 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.microsoft.azure.maven.webapp.utils.Utils.findStringInCollectionIgnoreCase;
+import static com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils.fromAppService;
/**
* Init or edit the configuration of azure webapp maven plugin.
@@ -84,8 +83,6 @@ public class ConfigMojo extends AbstractWebAppMojo {
private static final String NO_JAVA_WEB_APPS = "There are no Java Web Apps in current subscription, please follow the following steps to create a new one.";
private static final String LONG_LOADING_HINT = "It may take a few minutes to load all Java Web Apps, please be patient.";
private static final String[] configTypes = {"Application", "Runtime", "DeploymentSlot"};
- private static final String SETTING_DOCKER_IMAGE = "DOCKER_CUSTOM_IMAGE_NAME";
- private static final String SETTING_REGISTRY_SERVER = "DOCKER_REGISTRY_SERVER_URL";
private static final String SETTING_REGISTRY_USERNAME = "DOCKER_REGISTRY_SERVER_USERNAME";
private static final String SERVER_ID_TEMPLATE = "Please add a server in Maven settings.xml related to username: %s and put the serverId here";
@@ -466,7 +463,7 @@ private boolean isJarProject() {
private WebAppConfiguration getWebAppConfiguration() {
validateConfiguration(message -> AzureMessager.getMessager().warning(message.getMessage()), false);
- return new ConfigParser(this).getWebAppConfiguration();
+ return getConfigParser().getWebAppConfiguration();
}
private WebAppConfiguration chooseExistingWebappForConfiguration()
@@ -501,17 +498,12 @@ private WebAppConfiguration chooseExistingWebappForConfiguration()
}
final IWebApp webapp = az.webapp(selectedApp.getId());
- final String serverPlanId = selectedApp.getServicePlanId();
- IAppServicePlan servicePlan = null;
- if (StringUtils.isNotBlank(serverPlanId)) {
- servicePlan = az.appServicePlan(serverPlanId);
- }
final WebAppConfiguration.WebAppConfigurationBuilder, ?> builder = WebAppConfiguration.builder();
if (!AppServiceUtils.isDockerAppService(webapp)) {
builder.resources(Deployment.getDefaultDeploymentConfiguration(getProject().getPackaging()).getResources());
}
- return getConfigurationFromExisting(webapp, servicePlan, builder);
+ return getConfigurationFromExisting(webapp, builder);
} catch (AzureToolkitAuthenticationException ex) {
// if is valid for config goal to have error in authentication
getLog().warn(String.format("Cannot authenticate due to error: %s, select existing webapp is skipped.", ex.getMessage()));
@@ -534,43 +526,30 @@ private static WebAppOption selectAzureWebApp(TextIO textIO, List
.read(String.format("%s Web Apps in subscription %s:", webAppType, TextUtils.blue(targetSubscription.getName())));
}
- private static WebAppConfiguration getConfigurationFromExisting(IWebApp webapp, IAppServicePlan servicePlan,
+ private WebAppConfiguration getConfigurationFromExisting(IWebApp webapp,
WebAppConfiguration.WebAppConfigurationBuilder, ?> builder) {
+ final AppServiceConfig appServiceConfig = fromAppService(webapp, webapp.plan());
// common configuration
- builder.appName(webapp.name())
- .resourceGroup(webapp.entity().getResourceGroup())
- .subscriptionId(Utils.getSubscriptionId(webapp.id()))
- .region(webapp.entity().getRegion());
-
+ builder.appName(appServiceConfig.appName())
+ .resourceGroup(appServiceConfig.resourceGroup())
+ .subscriptionId(appServiceConfig.subscriptionId())
+ .region(appServiceConfig.region());
+ builder.os(appServiceConfig.runtime().os());
if (AppServiceUtils.isDockerAppService(webapp)) {
- builder.os(OperatingSystem.DOCKER);
final Map settings = webapp.entity().getAppSettings();
-
- final String imageSetting = settings.get(SETTING_DOCKER_IMAGE);
- if (StringUtils.isNotBlank(imageSetting)) {
- builder.image(imageSetting);
- } else {
- builder.image(webapp.entity().getDockerImageName());
- }
- final String registryServerSetting = settings.get(SETTING_REGISTRY_SERVER);
- if (StringUtils.isNotBlank(registryServerSetting)) {
- builder.registryUrl(registryServerSetting);
- }
-
+ builder.image(appServiceConfig.runtime().image());
+ builder.registryUrl(appServiceConfig.runtime().registryUrl());
final String dockerUsernameSetting = settings.get(SETTING_REGISTRY_USERNAME);
if (StringUtils.isNotBlank(dockerUsernameSetting)) {
builder.serverId(String.format(SERVER_ID_TEMPLATE, dockerUsernameSetting));
}
} else {
- builder.os(webapp.getRuntime().getOperatingSystem());
- builder.webContainer(Objects.toString(webapp.getRuntime().getWebContainer()));
- builder.javaVersion(Objects.toString(webapp.getRuntime().getJavaVersion()));
- }
- if (servicePlan != null && servicePlan.entity() != null) {
- builder.pricingTier(Optional.ofNullable(servicePlan.entity().getPricingTier()).map(Object::toString).orElse(null));
- builder.servicePlanName(servicePlan.name());
- builder.servicePlanResourceGroup(servicePlan.entity().getResourceGroup());
+ builder.webContainer(Objects.toString(appServiceConfig.runtime().webContainer()));
+ builder.javaVersion(Objects.toString(appServiceConfig.runtime().javaVersion()));
}
+ builder.servicePlanName(appServiceConfig.servicePlanName());
+ builder.servicePlanResourceGroup(appServiceConfig.servicePlanResourceGroup());
+ builder.pricingTier(Objects.toString(appServiceConfig.pricingTier()));
return builder.build();
}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/DeployMojo.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/DeployMojo.java
index ee4e3c6422..662a86a448 100644
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/DeployMojo.java
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/DeployMojo.java
@@ -5,294 +5,138 @@
package com.microsoft.azure.maven.webapp;
-import com.azure.core.management.exception.ManagementException;
-import com.azure.resourcemanager.AzureResourceManager;
-import com.azure.resourcemanager.resources.models.ResourceGroup;
import com.microsoft.azure.maven.model.DeploymentResource;
-import com.microsoft.azure.maven.webapp.utils.DeployUtils;
-import com.microsoft.azure.maven.webapp.utils.Utils;
-import com.microsoft.azure.maven.webapp.utils.WebAppUtils;
-import com.microsoft.azure.toolkit.lib.appservice.model.DeployType;
+import com.microsoft.azure.maven.webapp.configuration.DeploymentSlotConfig;
+import com.microsoft.azure.maven.webapp.task.DeployExternalResourcesTask;
+import com.microsoft.azure.toolkit.lib.Azure;
+import com.microsoft.azure.toolkit.lib.appservice.AzureAppService;
+import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
+import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
+import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
import com.microsoft.azure.toolkit.lib.appservice.model.WebAppArtifact;
import com.microsoft.azure.toolkit.lib.appservice.model.WebContainer;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppService;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppServicePlan;
import com.microsoft.azure.toolkit.lib.appservice.service.IWebApp;
import com.microsoft.azure.toolkit.lib.appservice.service.IWebAppBase;
import com.microsoft.azure.toolkit.lib.appservice.service.IWebAppDeploymentSlot;
+import com.microsoft.azure.toolkit.lib.appservice.task.CreateOrUpdateWebAppTask;
+import com.microsoft.azure.toolkit.lib.appservice.task.DeployWebAppTask;
+import com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils;
+import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
-import com.microsoft.azure.toolkit.lib.common.model.Region;
-import org.apache.commons.collections4.CollectionUtils;
-import org.apache.commons.io.FileUtils;
+import com.microsoft.azure.toolkit.lib.common.operation.AzureOperation;
+import com.microsoft.azure.toolkit.lib.common.utils.Utils;
+import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.artifact.versioning.ComparableVersion;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
-import org.zeroturnaround.zip.ZipUtil;
import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
-import java.util.function.Predicate;
-import java.util.stream.Collectors;
+
+import static com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils.fromAppService;
+import static com.microsoft.azure.toolkit.lib.appservice.utils.AppServiceConfigUtils.mergeAppServiceConfig;
+import static com.microsoft.azure.toolkit.lib.appservice.utils.Utils.throwForbidCreateResourceWarning;
/**
* Deploy an Azure Web App, either Windows-based or Linux-based.
*/
@Mojo(name = "deploy", defaultPhase = LifecyclePhase.DEPLOY)
public class DeployMojo extends AbstractWebAppMojo {
- private static final String CREATE_WEBAPP = "Creating web app %s...";
- private static final String CREATE_WEB_APP_DONE = "Successfully created Web App %s.";
- private static final String UPDATE_WEBAPP = "Updating target Web App %s...";
- private static final String UPDATE_WEBAPP_DONE = "Successfully updated Web App %s.";
- private static final String CREATE_RESOURCE_GROUP = "Creating resource group %s in region %s...";
- private static final String CREATE_RESOURCE_GROUP_DONE = "Successfully created resource group %s.";
- private static final String CREATE_APP_SERVICE_PLAN = "Creating app service plan...";
- private static final String CREATE_APP_SERVICE_DONE = "Successfully created app service plan %s.";
private static final String WEBAPP_NOT_EXIST_FOR_SLOT = "The Web App specified in pom.xml does not exist. " +
"Please make sure the Web App name is correct.";
private static final String CREATE_DEPLOYMENT_SLOT = "Creating deployment slot %s in web app %s";
private static final String CREATE_DEPLOYMENT_SLOT_DONE = "Successfully created the Deployment Slot.";
- private static final String DEPLOY_START = "Trying to deploy artifact to %s...";
- private static final String DEPLOY_FINISH = "Successfully deployed the artifact to https://%s";
- private static final String SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE = "Skip deployment for docker app service";
- private static final String NO_RUNTIME_CONFIG = "You need to specified in pom.xml for creating azure webapps.";
- private static final String CREATE_NEW_APP_SERVICE_PLAN = "createNewAppServicePlan";
- private static final String CREATE_NEW_RESOURCE_GROUP = "createNewResourceGroup";
- private static final String CREATE_NEW_WEB_APP = "createNewWebApp";
private static final String CREATE_NEW_DEPLOYMENT_SLOT = "createNewDeploymentSlot";
@Override
+ @AzureOperation(name = "webapp|mojo.deploy", type = AzureOperation.Type.ACTION)
protected void doExecute() throws AzureExecutionException {
validateConfiguration(message -> AzureMessager.getMessager().error(message.getMessage()), true);
// initialize library client
az = getOrCreateAzureAppServiceClient();
-
- final WebAppConfig config = getWebAppConfig();
- final IWebAppBase target = createOrUpdateResource(config);
- deploy(target, config);
- }
-
- private IWebAppBase createOrUpdateResource(final WebAppConfig config) throws AzureExecutionException {
- if (StringUtils.isEmpty(config.getDeploymentSlotName())) {
- final IWebApp webApp = getWebApp(config);
- return webApp.exists() ? updateWebApp(webApp, config) : createWebApp(webApp, config);
+ final IWebAppBase> target = createOrUpdateResource();
+ deployExternalResources(target, getConfigParser().getExternalArtifacts());
+ deploy(target, getConfigParser().getArtifacts());
+ updateTelemetryProperties();
+ }
+
+ private IWebAppBase> createOrUpdateResource() throws AzureExecutionException {
+ final boolean skipCreate = skipAzureResourceCreate || skipCreateAzureResource;
+ if (!isDeployToDeploymentSlot()) {
+ final AppServiceConfig appServiceConfig = getConfigParser().getAppServiceConfig();
+ IWebApp app = Azure.az(AzureAppService.class).webapp(appServiceConfig.resourceGroup(), appServiceConfig.appName());
+ final boolean newWebApp = !app.exists();
+ AppServiceConfig defaultConfig = !newWebApp ? fromAppService(app, app.plan()) : buildDefaultConfig(appServiceConfig.subscriptionId(),
+ appServiceConfig.resourceGroup(), appServiceConfig.appName());
+ mergeAppServiceConfig(appServiceConfig, defaultConfig);
+ if (appServiceConfig.pricingTier() == null) {
+ appServiceConfig.pricingTier(appServiceConfig.runtime().webContainer() == WebContainer.JBOSS_7 ? PricingTier.PREMIUM_P1V3 : PricingTier.PREMIUM_P1V2);
+ }
+ final CreateOrUpdateWebAppTask task = new CreateOrUpdateWebAppTask(appServiceConfig);
+ task.setSkipCreateAzureResource(skipCreate);
+ return task.execute();
} else {
+ // todo: New CreateOrUpdateDeploymentSlotTask
+ final DeploymentSlotConfig config = getConfigParser().getDeploymentSlotConfig();
final IWebAppDeploymentSlot slot = getDeploymentSlot(config);
- return slot.exists() ? updateDeploymentSlot(slot, config) : createDeploymentSlot(slot, config);
- }
- }
-
- private IWebApp getWebApp(final WebAppConfig config) {
- return az.webapp(config.getResourceGroup(), config.getAppName());
- }
-
- private IWebAppDeploymentSlot getDeploymentSlot(final WebAppConfig config) throws AzureExecutionException {
- final IWebApp webApp = getWebApp(config);
- if (!webApp.exists()) {
- throw new AzureExecutionException(WEBAPP_NOT_EXIST_FOR_SLOT);
- }
- return webApp.deploymentSlot(config.getDeploymentSlotName());
- }
-
- private IWebApp createWebApp(final IWebApp webApp, final WebAppConfig webAppConfig) throws AzureExecutionException {
- if (webAppConfig.getRuntime() == null) {
- throw new AzureExecutionException(NO_RUNTIME_CONFIG);
+ final boolean slotExists = slot.exists();
+ if (!slotExists && skipCreate) {
+ throwForbidCreateResourceWarning("Deployment slot", config.getName());
+ }
+ return slotExists ? updateDeploymentSlot(slot, config) : createDeploymentSlot(slot, config);
}
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_WEB_APP, String.valueOf(true));
- final ResourceGroup resourceGroup = getOrCreateResourceGroup(webAppConfig);
- final IAppServicePlan appServicePlan = getOrCreateAppServicePlan(webAppConfig);
- AzureMessager.getMessager().info(String.format(CREATE_WEBAPP, webAppConfig.getAppName()));
- final IWebApp result = webApp.create().withName(webAppConfig.getAppName())
- .withResourceGroup(resourceGroup.name())
- .withPlan(appServicePlan.id())
- .withRuntime(webAppConfig.getRuntime())
- .withDockerConfiguration(webAppConfig.getDockerConfiguration())
- .withAppSettings(webAppConfig.getAppSettings())
- .commit();
- AzureMessager.getMessager().info(String.format(CREATE_WEB_APP_DONE, result.name()));
- return result;
}
- private IWebApp updateWebApp(final IWebApp webApp, final WebAppConfig webAppConfig) {
- // update app service plan
- AzureMessager.getMessager().info(String.format(UPDATE_WEBAPP, webApp.name()));
- final IAppServicePlan currentPlan = webApp.plan();
- IAppServicePlan targetServicePlan = StringUtils.isEmpty(webAppConfig.getServicePlanName()) ? currentPlan :
- az.appServicePlan(getServicePlanResourceGroup(webAppConfig), webAppConfig.getServicePlanName());
- if (!targetServicePlan.exists()) {
- targetServicePlan = getOrCreateAppServicePlan(webAppConfig);
- } else {
- if (region != null && !Objects.equals(Region.fromName(region), Region.fromName(targetServicePlan.entity().getRegion()))) {
- AzureMessager.getMessager().warning(String.format("Skip region update for existing service plan '%s' since it is not allowed.",
- targetServicePlan.name()));
- }
-
- if (webAppConfig.getPricingTier() != null) {
- targetServicePlan.update().withPricingTier(webAppConfig.getPricingTier()).commit();
+ private AppServiceConfig buildDefaultConfig(String subscriptionId, String resourceGroup, String appName) {
+ ComparableVersion javaVersionForProject = null;
+ final String outputFileName = project.getBuild().getFinalName() + "." + project.getPackaging();
+ File outputFile = new File(project.getBuild().getDirectory(), outputFileName);
+ if (outputFile.exists() && StringUtils.equalsIgnoreCase("jar", project.getPackaging())) {
+ try {
+ javaVersionForProject = new ComparableVersion(Utils.getArtifactCompileVersion(outputFile));
+ } catch (Exception e) {
+ // it is acceptable that java version from jar file cannot be retrieved
}
}
- final IWebApp result = webApp.update().withPlan(targetServicePlan.id())
- .withRuntime(webAppConfig.getRuntime())
- .withDockerConfiguration(webAppConfig.getDockerConfiguration())
- .withAppSettings(webAppConfig.getAppSettings())
- .commit();
- AzureMessager.getMessager().info(String.format(UPDATE_WEBAPP_DONE, webApp.name()));
- return result;
- }
-
- private ResourceGroup getOrCreateResourceGroup(final WebAppConfig webAppConfig) {
- // todo: Extract resource group logic to library
- final AzureResourceManager azureResourceManager = az.getAzureResourceManager(webAppConfig.getSubscriptionId());
- try {
- return azureResourceManager.resourceGroups().getByName(webAppConfig.getResourceGroup());
- } catch (ManagementException e) {
- AzureMessager.getMessager().info(String.format(CREATE_RESOURCE_GROUP, webAppConfig.getResourceGroup(), webAppConfig.getRegion().getName()));
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_RESOURCE_GROUP, String.valueOf(true));
- final ResourceGroup result = azureResourceManager.resourceGroups().define(webAppConfig.getResourceGroup())
- .withRegion(webAppConfig.getRegion().getName()).create();
- AzureMessager.getMessager().info(String.format(CREATE_RESOURCE_GROUP_DONE, webAppConfig.getResourceGroup()));
- return result;
- }
+ javaVersionForProject = ObjectUtils.firstNonNull(javaVersionForProject, new ComparableVersion(System.getProperty("java.version")));
+ // get java version according to project java version
+ JavaVersion javaVersion = javaVersionForProject.compareTo(new ComparableVersion("9")) < 0 ? JavaVersion.JAVA_8 : JavaVersion.JAVA_11;
+ return AppServiceConfigUtils.buildDefaultWebAppConfig(subscriptionId, resourceGroup, appName, this.project.getPackaging(), javaVersion);
}
- private IAppServicePlan getOrCreateAppServicePlan(final WebAppConfig webAppConfig) {
- final String servicePlanName = StringUtils.isEmpty(webAppConfig.getServicePlanName()) ?
- getNewAppServicePlanName(webAppConfig) : webAppConfig.getServicePlanName();
- final String servicePlanGroup = getServicePlanResourceGroup(webAppConfig);
- final IAppServicePlan appServicePlan = az.appServicePlan(servicePlanGroup, servicePlanName);
- if (!appServicePlan.exists()) {
- AzureMessager.getMessager().info(CREATE_APP_SERVICE_PLAN);
- getTelemetryProxy().addDefaultProperty(CREATE_NEW_APP_SERVICE_PLAN, String.valueOf(true));
- appServicePlan.create()
- .withName(servicePlanName)
- .withResourceGroup(servicePlanGroup)
- .withRegion(webAppConfig.getRegion())
- .withPricingTier(webAppConfig.getPricingTier())
- .withOperatingSystem(webAppConfig.getRuntime().getOperatingSystem())
- .commit();
- AzureMessager.getMessager().info(String.format(CREATE_APP_SERVICE_DONE, appServicePlan.name()));
+ private IWebAppDeploymentSlot getDeploymentSlot(final DeploymentSlotConfig config) throws AzureExecutionException {
+ final IWebApp webApp = az.webapp(config.getResourceGroup(), config.getAppName());
+ if (!webApp.exists()) {
+ throw new AzureExecutionException(WEBAPP_NOT_EXIST_FOR_SLOT);
}
- return appServicePlan;
- }
-
- private String getNewAppServicePlanName(final WebAppConfig webAppConfig) {
- return StringUtils.isEmpty(webAppConfig.getServicePlanName()) ? String.format("asp-%s", webAppConfig.getAppName()) :
- webAppConfig.getServicePlanName();
+ return webApp.deploymentSlot(config.getName());
}
- private String getServicePlanResourceGroup(final WebAppConfig webAppConfig) {
- return StringUtils.isEmpty(webAppConfig.getServicePlanResourceGroup()) ? webAppConfig.getResourceGroup() :
- webAppConfig.getServicePlanResourceGroup();
- }
-
- private IWebAppDeploymentSlot createDeploymentSlot(final IWebAppDeploymentSlot slot, final WebAppConfig webAppConfig) {
- AzureMessager.getMessager().info(String.format(CREATE_DEPLOYMENT_SLOT, webAppConfig.getDeploymentSlotName(), webAppConfig.getAppName()));
+ private IWebAppDeploymentSlot createDeploymentSlot(final IWebAppDeploymentSlot slot, final DeploymentSlotConfig slotConfig) {
+ AzureMessager.getMessager().info(AzureString.format(CREATE_DEPLOYMENT_SLOT, slotConfig.getName(), slotConfig.getAppName()));
getTelemetryProxy().addDefaultProperty(CREATE_NEW_DEPLOYMENT_SLOT, String.valueOf(true));
- final IWebAppDeploymentSlot result = slot.create().withName(webAppConfig.getDeploymentSlotName())
- .withConfigurationSource(webAppConfig.getDeploymentSlotConfigurationSource())
- .withAppSettings(webAppConfig.getAppSettings())
+ final IWebAppDeploymentSlot result = slot.create().withName(slotConfig.getName())
+ .withConfigurationSource(slotConfig.getConfigurationSource())
+ .withAppSettings(slotConfig.getAppSettings())
.commit();
AzureMessager.getMessager().info(CREATE_DEPLOYMENT_SLOT_DONE);
return result;
}
- private void deploy(IWebAppBase target, WebAppConfig config) throws AzureExecutionException {
- if (target.getRuntime().isDocker()) {
- AzureMessager.getMessager().info(SKIP_DEPLOYMENT_FOR_DOCKER_APP_SERVICE);
- return;
- }
- try {
- AzureMessager.getMessager().info(String.format(DEPLOY_START, config.getAppName()));
- if (isStopAppDuringDeployment()) {
- WebAppUtils.stopAppService(target);
- }
- deployArtifacts(target, config);
- deployExternalResources(target);
- AzureMessager.getMessager().info(String.format(DEPLOY_FINISH, target.hostName()));
- } finally {
- WebAppUtils.startAppService(target);
- }
- }
-
// update existing slot is not supported in current version, will implement it later
- private IWebAppDeploymentSlot updateDeploymentSlot(final IWebAppDeploymentSlot slot, final WebAppConfig webAppConfig) {
+ private IWebAppDeploymentSlot updateDeploymentSlot(final IWebAppDeploymentSlot slot, final DeploymentSlotConfig slotConfig) {
+ AzureMessager.getMessager().warning("update existing slot is not supported in current version");
return slot;
}
- private void deployArtifacts(IWebAppBase target, WebAppConfig config) throws AzureExecutionException {
- final List artifactsOneDeploy = config.getWebAppArtifacts().stream()
- .filter(artifact -> artifact.getDeployType() != null)
- .collect(Collectors.toList());
- artifactsOneDeploy.forEach(resource -> target.deploy(resource.getDeployType(), resource.getFile(), resource.getPath()));
-
- // This is the codes for one deploy API, for current release, will replace it with zip all files and deploy with zip deploy
- final List artifacts = config.getWebAppArtifacts().stream()
- .filter(artifact -> artifact.getDeployType() == null)
- .collect(Collectors.toList());
-
- if (CollectionUtils.isEmpty(artifacts)) {
- return;
- }
- // call correspond deploy method when deploy artifact only
- if (artifacts.size() == 1) {
- final WebAppArtifact artifact = artifacts.get(0);
- final DeployType deployType = DeployType.getDeployTypeFromFile(artifact.getFile());
- target.deploy(deployType, artifact.getFile(), artifact.getPath());
- return;
- }
- // Support deploy multi war to different paths
- if (DeployUtils.isAllWarArtifacts(artifacts)) {
- artifacts.forEach(resource -> target.deploy(DeployType.getDeployTypeFromFile(resource.getFile()), resource.getFile(), resource.getPath()));
- return;
- }
- // package all resource and do zip deploy
- // todo: migrate to use one deploy
- deployArtifactsWithZipDeploy(target, artifacts);
- }
-
- private void deployArtifactsWithZipDeploy(IWebAppBase target, List artifacts) throws AzureExecutionException {
- final File stagingDirectory = prepareStagingDirectory(artifacts);
- // Rename jar once java_se runtime
- if (Objects.equals(target.getRuntime().getWebContainer(), WebContainer.JAVA_SE)) {
- final List files = new ArrayList<>(FileUtils.listFiles(stagingDirectory, null, true));
- DeployUtils.prepareJavaSERuntimeJarArtifact(files, project.getBuild().getFinalName());
- }
- final File zipFile = Utils.createTempFile(appName + UUID.randomUUID(), ".zip");
- ZipUtil.pack(stagingDirectory, zipFile);
- // Deploy zip with zip deploy
- target.deploy(DeployType.ZIP, zipFile);
- }
-
- private static File prepareStagingDirectory(List webAppArtifacts) throws AzureExecutionException {
- try {
- final File stagingDirectory = Files.createTempDirectory("azure-functions").toFile();
- FileUtils.forceDeleteOnExit(stagingDirectory);
- // Copy maven artifacts to staging folder
- for (final WebAppArtifact webAppArtifact : webAppArtifacts) {
- final File targetFolder = StringUtils.isEmpty(webAppArtifact.getPath()) ? stagingDirectory :
- new File(stagingDirectory, webAppArtifact.getPath());
- FileUtils.copyFileToDirectory(webAppArtifact.getFile(), targetFolder);
- }
- return stagingDirectory;
- } catch (IOException e) {
- throw new AzureExecutionException("Failed to package resources", e);
- }
- }
-
- private void deployExternalResources(IAppService target) throws AzureExecutionException {
- DeployUtils.deployResourcesWithFtp(target, filterResources(DeploymentResource::isExternalResource));
+ private void deploy(IWebAppBase> target, List artifacts) {
+ new DeployWebAppTask(target, artifacts, isStopAppDuringDeployment()).execute();
}
- private List filterResources(Predicate predicate) {
- final List resources = this.deployment == null ? Collections.emptyList() : this.deployment.getResources();
- return resources.stream()
- .filter(predicate).collect(Collectors.toList());
+ private void deployExternalResources(final IWebAppBase> target, final List resources) {
+ new DeployExternalResourcesTask(target, resources).execute();
}
}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfig.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfig.java
deleted file mode 100644
index e2a2ca6a41..0000000000
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfig.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.maven.webapp;
-
-import com.microsoft.azure.toolkit.lib.appservice.model.WebAppArtifact;
-import com.microsoft.azure.toolkit.lib.appservice.model.DockerConfiguration;
-import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
-import com.microsoft.azure.toolkit.lib.appservice.model.Runtime;
-import com.microsoft.azure.toolkit.lib.common.model.Region;
-import lombok.Getter;
-import lombok.experimental.SuperBuilder;
-
-import java.util.List;
-import java.util.Map;
-
-@Getter
-@SuperBuilder(toBuilder = true)
-public class WebAppConfig {
- private String subscriptionId;
- private String resourceGroup;
- private String appName;
- private String servicePlanName;
- private String servicePlanResourceGroup;
- private Region region;
- private PricingTier pricingTier;
- private Runtime runtime;
- private DockerConfiguration dockerConfiguration;
- private String deploymentSlotName;
- private String deploymentSlotConfigurationSource;
- private Map appSettings;
- // resources
- private List webAppArtifacts;
-}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfiguration.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfiguration.java
index 26270d2833..7c30333126 100644
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfiguration.java
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/WebAppConfiguration.java
@@ -29,7 +29,7 @@
@SuperBuilder(toBuilder = true)
public class WebAppConfiguration {
public static final PricingTier DEFAULT_JBOSS_PRICING_TIER = PricingTier.PREMIUM_P1V3;
- public static final Region DEFAULT_REGION = Region.EUROPE_WEST;
+ public static final Region DEFAULT_REGION = Region.US_CENTRAL;
public static final PricingTier DEFAULT_PRICINGTIER = PricingTier.PREMIUM_P1V2;
public static final JavaVersion DEFAULT_JAVA_VERSION = JavaVersion.JAVA_8;
public static final WebContainer DEFAULT_CONTAINER = WebContainer.TOMCAT_85;
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/configuration/DeploymentSlotConfig.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/configuration/DeploymentSlotConfig.java
new file mode 100644
index 0000000000..fe5d19dc95
--- /dev/null
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/configuration/DeploymentSlotConfig.java
@@ -0,0 +1,21 @@
+/*
+ * 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.maven.webapp.configuration;
+
+import lombok.Builder;
+import lombok.Getter;
+
+import java.util.Map;
+
+@Getter
+@Builder
+public class DeploymentSlotConfig {
+ private final String subscriptionId;
+ private final String resourceGroup;
+ private final String appName;
+ private final String name;
+ private final String configurationSource;
+ private final Map appSettings;
+}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/parser/ConfigParser.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/parser/ConfigParser.java
index 07d8777963..01b47131bd 100644
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/parser/ConfigParser.java
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/parser/ConfigParser.java
@@ -9,12 +9,13 @@
import com.microsoft.azure.maven.model.DeploymentResource;
import com.microsoft.azure.maven.utils.MavenArtifactUtils;
import com.microsoft.azure.maven.webapp.AbstractWebAppMojo;
-import com.microsoft.azure.maven.webapp.WebAppConfig;
import com.microsoft.azure.maven.webapp.WebAppConfiguration;
import com.microsoft.azure.maven.webapp.configuration.Deployment;
+import com.microsoft.azure.maven.webapp.configuration.DeploymentSlotConfig;
import com.microsoft.azure.maven.webapp.configuration.MavenRuntimeConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig;
+import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig;
import com.microsoft.azure.toolkit.lib.appservice.model.DeployType;
-import com.microsoft.azure.toolkit.lib.appservice.model.DockerConfiguration;
import com.microsoft.azure.toolkit.lib.appservice.model.JavaVersion;
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem;
import com.microsoft.azure.toolkit.lib.appservice.model.PricingTier;
@@ -59,6 +60,87 @@ public ConfigParser(AbstractWebAppMojo mojo) {
this.mojo = mojo;
}
+ public AppServiceConfig getAppServiceConfig() throws AzureExecutionException {
+ return new AppServiceConfig()
+ .subscriptionId(getSubscriptionId())
+ .resourceGroup(getResourceGroup())
+ .appName(getAppName())
+ .servicePlanName(getAppServicePlanName())
+ .servicePlanResourceGroup(getAppServicePlanResourceGroup())
+ .deploymentSlotName(getDeploymentSlotName())
+ .deploymentSlotConfigurationSource(getDeploymentSlotConfigurationSource())
+ .pricingTier(getPricingTier())
+ .region(getRegion())
+ .runtime(getRuntimeConfig())
+ .appSettings(mojo.getAppSettings());
+ }
+
+ // todo: replace WebAppConfiguration with WebAppConfig
+ public WebAppConfiguration getWebAppConfiguration() {
+ WebAppConfiguration.WebAppConfigurationBuilder, ?> builder = WebAppConfiguration.builder();
+ final Runtime runtime = getRuntime();
+ final OperatingSystem os = Optional.ofNullable(runtime).map(Runtime::getOperatingSystem).orElse(null);
+ if (os == null) {
+ Log.debug("No runtime related config is specified. It will cause error if creating a new web app.");
+ } else {
+ switch (os) {
+ case WINDOWS:
+ case LINUX:
+ builder = builder.javaVersion(Objects.toString(runtime.getJavaVersion())).webContainer(Objects.toString(runtime.getWebContainer()));
+ break;
+ case DOCKER:
+ final MavenRuntimeConfig runtimeConfig = mojo.getRuntime();
+ builder = builder.image(runtimeConfig.getImage()).serverId(runtimeConfig.getServerId()).registryUrl(runtimeConfig.getRegistryUrl());
+ break;
+ default:
+ Log.debug("Invalid operating system from the configuration.");
+ }
+ }
+ return builder.appName(getAppName())
+ .resourceGroup(getResourceGroup())
+ .region(getRegion())
+ .pricingTier(Optional.ofNullable(getPricingTier()).map(PricingTier::getSize).orElse(null))
+ .servicePlanName(mojo.getAppServicePlanName())
+ .servicePlanResourceGroup(mojo.getAppServicePlanResourceGroup())
+ .deploymentSlotSetting(mojo.getDeploymentSlotSetting())
+ .os(os)
+ .mavenSettings(mojo.getSettings())
+ .resources(Optional.ofNullable(mojo.getDeployment()).map(Deployment::getResources).orElse(null))
+ .stagingDirectoryPath(mojo.getDeploymentStagingDirectoryPath())
+ .buildDirectoryAbsolutePath(mojo.getBuildDirectoryAbsolutePath())
+ .project(mojo.getProject())
+ .session(mojo.getSession())
+ .filtering(mojo.getMavenResourcesFiltering())
+ .schemaVersion("v2")
+ .build();
+ }
+
+ public DeploymentSlotConfig getDeploymentSlotConfig() {
+ return DeploymentSlotConfig.builder()
+ .subscriptionId(getSubscriptionId())
+ .resourceGroup(getResourceGroup())
+ .appName(getAppName())
+ .name(getDeploymentSlotName())
+ .configurationSource(getDeploymentSlotConfigurationSource())
+ .appSettings(mojo.getAppSettings())
+ .build();
+ }
+
+ public List getArtifacts() throws AzureExecutionException {
+ if (mojo.getDeployment() == null || mojo.getDeployment().getResources() == null) {
+ return Collections.emptyList();
+ }
+ return convertResourceToArtifacts(mojo.getDeployment().getResources());
+ }
+
+ public List getExternalArtifacts() {
+ if (mojo.getDeployment() == null || mojo.getDeployment().getResources() == null) {
+ return Collections.emptyList();
+ }
+ return mojo.getDeployment().getResources().stream()
+ .filter(DeploymentResource::isExternalResource).collect(Collectors.toList());
+ }
+
public String getAppName() {
return mojo.getAppName();
}
@@ -76,6 +158,9 @@ public String getDeploymentSlotConfigurationSource() {
}
public PricingTier getPricingTier() {
+ if (StringUtils.isEmpty(mojo.getPricingTier())) {
+ return null;
+ }
return parseExpandableParameter(input -> {
if (StringUtils.contains(mojo.getPricingTier(), "_")) {
final String[] pricingParams = mojo.getPricingTier().split("_");
@@ -99,31 +184,10 @@ public String getSubscriptionId() {
}
public Region getRegion() {
- return parseExpandableParameter(Region::fromName, mojo.getRegion(), EXPANDABLE_REGION_WARNING);
- }
-
- public DockerConfiguration getDockerConfiguration() throws AzureExecutionException {
- final MavenRuntimeConfig runtime = mojo.getRuntime();
- if (runtime == null) {
+ if (StringUtils.isEmpty(mojo.getRegion())) {
return null;
}
- final OperatingSystem os = getOs(runtime);
- if (os != OperatingSystem.DOCKER) {
- return null;
- }
- final MavenDockerCredentialProvider credentialProvider = getDockerCredential(runtime.getServerId());
- return DockerConfiguration.builder()
- .registryUrl(runtime.getRegistryUrl())
- .image(runtime.getImage())
- .userName(credentialProvider.getUsername())
- .password(credentialProvider.getPassword()).build();
- }
-
- public List getMavenArtifacts() throws AzureExecutionException {
- if (mojo.getDeployment() == null || mojo.getDeployment().getResources() == null) {
- return Collections.emptyList();
- }
- return convertResourceToArtifacts(mojo.getDeployment().getResources());
+ return parseExpandableParameter(Region::fromName, mojo.getRegion(), EXPANDABLE_REGION_WARNING);
}
public Runtime getRuntime() {
@@ -135,8 +199,10 @@ public Runtime getRuntime() {
if (os == OperatingSystem.DOCKER) {
return Runtime.DOCKER;
}
- final JavaVersion javaVersion = parseExpandableParameter(JavaVersion::fromString, runtime.getJavaVersion(), EXPANDABLE_JAVA_VERSION_WARNING);
- final WebContainer webContainer = parseExpandableParameter(WebContainer::fromString, runtime.getWebContainer(), EXPANDABLE_WEB_CONTAINER_WARNING);
+ final JavaVersion javaVersion = StringUtils.isEmpty(runtime.getJavaVersion()) ? null :
+ parseExpandableParameter(JavaVersion::fromString, runtime.getJavaVersion(), EXPANDABLE_JAVA_VERSION_WARNING);
+ final WebContainer webContainer = StringUtils.isEmpty(runtime.getWebContainer()) ? null :
+ parseExpandableParameter(WebContainer::fromString, runtime.getWebContainer(), EXPANDABLE_WEB_CONTAINER_WARNING);
return Runtime.getRuntime(os, webContainer, javaVersion);
}
@@ -144,62 +210,23 @@ private OperatingSystem getOs(final MavenRuntimeConfig runtime) {
return OperatingSystem.fromString(runtime.getOs());
}
- public WebAppConfig parse() throws AzureExecutionException {
- return WebAppConfig.builder()
- .subscriptionId(getSubscriptionId())
- .appName(getAppName())
- .resourceGroup(getResourceGroup())
- .servicePlanName(getAppServicePlanName())
- .servicePlanResourceGroup(getAppServicePlanResourceGroup())
- .pricingTier(getPricingTier())
- .region(getRegion())
- .runtime(getRuntime())
- .dockerConfiguration(getDockerConfiguration())
- .deploymentSlotName(getDeploymentSlotName())
- .deploymentSlotConfigurationSource(getDeploymentSlotConfigurationSource())
- .webAppArtifacts(getMavenArtifacts())
- .appSettings(this.mojo.getAppSettings())
- .build();
- }
-
- // todo: replace WebAppConfiguration with WebAppConfig
- public WebAppConfiguration getWebAppConfiguration() {
- WebAppConfiguration.WebAppConfigurationBuilder, ?> builder = WebAppConfiguration.builder();
- final Runtime runtime = getRuntime();
- final OperatingSystem os = Optional.ofNullable(runtime).map(Runtime::getOperatingSystem).orElse(null);
- if (os == null) {
- Log.debug("No runtime related config is specified. It will cause error if creating a new web app.");
- } else {
- switch (os) {
- case WINDOWS:
- case LINUX:
- builder = builder.javaVersion(Objects.toString(runtime.getJavaVersion())).webContainer(Objects.toString(runtime.getWebContainer()));
- break;
- case DOCKER:
- final MavenRuntimeConfig runtimeConfig = mojo.getRuntime();
- builder = builder.image(runtimeConfig.getImage()).serverId(runtimeConfig.getServerId()).registryUrl(runtimeConfig.getRegistryUrl());
- break;
- default:
- Log.debug("Invalid operating system from the configuration.");
- }
+ private RuntimeConfig getRuntimeConfig() throws AzureExecutionException {
+ final MavenRuntimeConfig runtime = mojo.getRuntime();
+ if (runtime == null || runtime.isEmpty()) {
+ return null;
}
- return builder.appName(getAppName())
- .resourceGroup(getResourceGroup())
- .region(getRegion())
- .pricingTier(getPricingTier().getSize())
- .servicePlanName(mojo.getAppServicePlanName())
- .servicePlanResourceGroup(mojo.getAppServicePlanResourceGroup())
- .deploymentSlotSetting(mojo.getDeploymentSlotSetting())
- .os(os)
- .mavenSettings(mojo.getSettings())
- .resources(Optional.ofNullable(mojo.getDeployment()).map(Deployment::getResources).orElse(null))
- .stagingDirectoryPath(mojo.getDeploymentStagingDirectoryPath())
- .buildDirectoryAbsolutePath(mojo.getBuildDirectoryAbsolutePath())
- .project(mojo.getProject())
- .session(mojo.getSession())
- .filtering(mojo.getMavenResourcesFiltering())
- .schemaVersion("v2")
- .build();
+ final OperatingSystem os = getOs(runtime);
+ final JavaVersion javaVersion = StringUtils.isEmpty(runtime.getJavaVersion()) ? null :
+ parseExpandableParameter(JavaVersion::fromString, runtime.getJavaVersion(), EXPANDABLE_JAVA_VERSION_WARNING);
+ final WebContainer webContainer = StringUtils.isEmpty(runtime.getWebContainer()) ? null :
+ parseExpandableParameter(WebContainer::fromString, runtime.getWebContainer(), EXPANDABLE_WEB_CONTAINER_WARNING);
+ final RuntimeConfig result = new RuntimeConfig().os(os).javaVersion(javaVersion).webContainer(webContainer)
+ .image(runtime.getImage()).registryUrl(runtime.getRegistryUrl());
+ if (StringUtils.isNotEmpty(runtime.getServerId())) {
+ final MavenDockerCredentialProvider credentialProvider = getDockerCredential(runtime.getServerId());
+ result.username(credentialProvider.getUsername()).password(credentialProvider.getPassword());
+ }
+ return result;
}
protected MavenDockerCredentialProvider getDockerCredential(String serverId) {
@@ -253,12 +280,10 @@ private static List convertOneDeployResourceToArtifacts(Resource
}
if (artifacts.isEmpty()) {
- Log.warn(String.format("Cannot find any files defined by resource(%s)",
- StringUtils.firstNonBlank(resource.toString())));
+ Log.warn(String.format("Cannot find any files defined by resource(%s)", StringUtils.firstNonBlank(resource.toString())));
}
if (type.ignorePath() && StringUtils.isNotBlank(resource.getTargetPath())) {
- throw new AzureToolkitRuntimeException(String.format("'' is not allowed for deployable type('%s').",
- type));
+ throw new AzureToolkitRuntimeException(String.format("'' is not allowed for deployable type('%s').", type));
}
if (StringUtils.isNotBlank(type.getFileExt())) {
final String expectFileExtension = type.getFileExt();
@@ -307,5 +332,4 @@ private static String normalizePath(String path) {
}
return StringUtils.removeEnd(path.replaceAll("([\\\\/])+", Matcher.quoteReplacement("/")), "/");
}
-
}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/task/DeployExternalResourcesTask.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/task/DeployExternalResourcesTask.java
new file mode 100644
index 0000000000..60efb20bc4
--- /dev/null
+++ b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/task/DeployExternalResourcesTask.java
@@ -0,0 +1,69 @@
+/*
+ * 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.maven.webapp.task;
+
+import com.microsoft.azure.maven.model.DeploymentResource;
+import com.microsoft.azure.maven.webapp.utils.FTPUtils;
+import com.microsoft.azure.maven.webapp.utils.Utils;
+import com.microsoft.azure.toolkit.lib.appservice.model.PublishingProfile;
+import com.microsoft.azure.toolkit.lib.appservice.service.IAppService;
+import com.microsoft.azure.toolkit.lib.appservice.service.IWebAppBase;
+import com.microsoft.azure.toolkit.lib.common.bundle.AzureString;
+import com.microsoft.azure.toolkit.lib.common.exception.AzureToolkitRuntimeException;
+import com.microsoft.azure.toolkit.lib.common.messager.AzureMessager;
+import com.microsoft.azure.toolkit.lib.common.task.AzureTask;
+import org.apache.commons.net.ftp.FTPClient;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+@Deprecated
+public class DeployExternalResourcesTask extends AzureTask> {
+ private static final String DEPLOY_START = "Trying to deploy external resources to %s...";
+ private static final String DEPLOY_FINISH = "Successfully deployed the resources to %s";
+
+ final IWebAppBase> target;
+ final List resources;
+
+ public DeployExternalResourcesTask(final IWebAppBase> target, final List resources) {
+ this.target = target;
+ this.resources = resources;
+ }
+
+ @Override
+ public IWebAppBase> execute() {
+ AzureMessager.getMessager().info(AzureString.format(DEPLOY_START, target.name()));
+ deployExternalResources(target, resources);
+ AzureMessager.getMessager().info(AzureString.format(DEPLOY_FINISH, target.name()));
+ return target;
+ }
+
+ private void deployExternalResources(final IAppService> target, final List resources) {
+ if (resources.isEmpty()) {
+ return;
+ }
+ AzureMessager.getMessager().info(AzureString.format("Uploading resources to %s", target.name()));
+ final PublishingProfile publishingProfile = target.getPublishingProfile();
+ final String serverUrl = publishingProfile.getFtpUrl().split("/", 2)[0];
+ try {
+ final FTPClient ftpClient = FTPUtils.getFTPClient(serverUrl, publishingProfile.getFtpUsername(), publishingProfile.getFtpPassword());
+ for (final DeploymentResource externalResource : resources) {
+ uploadResource(externalResource, ftpClient);
+ }
+ } catch (IOException e) {
+ throw new AzureToolkitRuntimeException(e.getMessage(), e);
+ }
+ }
+
+ private static void uploadResource(DeploymentResource resource, FTPClient ftpClient) throws IOException {
+ final List files = Utils.getArtifacts(resource);
+ final String target = resource.getAbsoluteTargetPath();
+ for (final File file : files) {
+ FTPUtils.uploadFile(ftpClient, file.getPath(), target);
+ }
+ }
+}
diff --git a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/utils/DeployUtils.java b/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/utils/DeployUtils.java
deleted file mode 100644
index 99eb90f6a1..0000000000
--- a/azure-webapp-maven-plugin/src/main/java/com/microsoft/azure/maven/webapp/utils/DeployUtils.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * 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.maven.webapp.utils;
-
-import com.microsoft.azure.toolkit.lib.common.exception.AzureExecutionException;
-import com.microsoft.azure.toolkit.lib.common.logging.Log;
-import com.microsoft.azure.maven.model.DeploymentResource;
-import com.microsoft.azure.toolkit.lib.appservice.model.WebAppArtifact;
-import com.microsoft.azure.toolkit.lib.appservice.model.DeployType;
-import com.microsoft.azure.toolkit.lib.appservice.model.PublishingProfile;
-import com.microsoft.azure.toolkit.lib.appservice.service.IAppService;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.net.ftp.FTPClient;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-import java.util.jar.JarInputStream;
-import java.util.jar.Manifest;
-import java.util.stream.Collectors;
-
-public class DeployUtils {
- private static final String DEFAULT_APP_SERVICE_JAR_NAME = "app.jar";
- private static final String WEB_CONFIG = "web.config";
- private static final String RENAMING_MESSAGE = "Renaming %s to %s";
- private static final String RENAMING_FAILED_MESSAGE = "Failed to rename artifact to %s, which is required in Java SE environment, " +
- "refer to https://docs.microsoft.com/en-us/azure/app-service/containers/configure-language-java#set-java-runtime-options for details.";
- private static final String NO_EXECUTABLE_JAR = "No executable jar found in target folder according to resource filter in , " +
- "please make sure the resource filter is correct and you have built the jar.";
- private static final String MULTI_EXECUTABLE_JARS = "Multi executable jars found in , please check the configuration";
-
- public static void deployResourcesWithFtp(IAppService appService, List externalResources) throws AzureExecutionException {
- if (externalResources.isEmpty()) {
- return;
- }
- final PublishingProfile publishingProfile = appService.getPublishingProfile();
- final String serverUrl = publishingProfile.getFtpUrl().split("/", 2)[0];
- try {
-
- final FTPClient ftpClient = FTPUtils.getFTPClient(serverUrl, publishingProfile.getFtpUsername(), publishingProfile.getFtpPassword());
- for (final DeploymentResource externalResource : externalResources) {
- uploadResource(externalResource, ftpClient);
- }
- } catch (IOException e) {
- throw new AzureExecutionException(e.getMessage(), e);
- }
- }
-
- public static boolean isAllWarArtifacts(List webAppArtifacts) {
- final Set deployTypes = webAppArtifacts.stream().map(WebAppArtifact::getDeployType).collect(Collectors.toSet());
- return deployTypes.size() == 1 && deployTypes.iterator().next() == DeployType.WAR;
- }
-
- private static void uploadResource(DeploymentResource resource, FTPClient ftpClient) throws IOException {
- final List files = Utils.getArtifacts(resource);
- final String target = resource.getAbsoluteTargetPath();
- for (final File file : files) {
- FTPUtils.uploadFile(ftpClient, file.getPath(), target);
- }
- }
-
- /**
- * Rename project jar to app.jar for java se app service
- */
- public static void prepareJavaSERuntimeJarArtifact(final List artifacts, final String finalName) throws AzureExecutionException {
- if (existsWebConfig(artifacts)) {
- return;
- }
- final File artifact = getProjectJarArtifact(artifacts, finalName);
- final File renamedArtifact = new File(artifact.getParent(), DEFAULT_APP_SERVICE_JAR_NAME);
- if (!StringUtils.equals(artifact.getName(), DEFAULT_APP_SERVICE_JAR_NAME)) {
- Log.info(String.format(RENAMING_MESSAGE, artifact.getAbsolutePath(), DEFAULT_APP_SERVICE_JAR_NAME));
- if (!artifact.renameTo(renamedArtifact)) {
- throw new AzureExecutionException(String.format(RENAMING_FAILED_MESSAGE, DEFAULT_APP_SERVICE_JAR_NAME));
- }
- }
- }
-
- private static File getProjectJarArtifact(final List artifacts, final String finalName) throws AzureExecutionException {
- final List executableArtifacts = artifacts.stream()
- .filter(DeployUtils::isExecutableJar).collect(Collectors.toList());
- final File finalArtifact = executableArtifacts.stream()
- .filter(file -> StringUtils.equals(finalName, file.getName())).findFirst().orElse(null);
- if (executableArtifacts.size() == 0) {
- throw new AzureExecutionException(NO_EXECUTABLE_JAR);
- } else if (finalArtifact == null && executableArtifacts.size() > 1) {
- throw new AzureExecutionException(MULTI_EXECUTABLE_JARS);
- }
- return finalArtifact == null ? executableArtifacts.get(0) : finalArtifact;
- }
-
- private static boolean existsWebConfig(final List artifacts) {
- return artifacts.stream().anyMatch(file -> StringUtils.equals(file.getName(), WEB_CONFIG));
- }
-
- private static boolean isExecutableJar(File file) {
- if (!StringUtils.equalsIgnoreCase(FilenameUtils.getExtension(file.getName()), "jar")) {
- return false;
- }
- try (final FileInputStream fileInputStream = new FileInputStream(file);
- final JarInputStream jarInputStream = new JarInputStream(fileInputStream)) {
- final Manifest manifest = jarInputStream.getManifest();
- return manifest != null && manifest.getMainAttributes().getValue("Main-Class") != null;
- } catch (IOException e) {
- return false;
- }
- }
-}
diff --git a/azure-webapp-maven-plugin/src/main/resources/schema/WebAppConfiguration.json b/azure-webapp-maven-plugin/src/main/resources/schema/WebAppConfiguration.json
index 9cd35a427f..d08b331353 100644
--- a/azure-webapp-maven-plugin/src/main/resources/schema/WebAppConfiguration.json
+++ b/azure-webapp-maven-plugin/src/main/resources/schema/WebAppConfiguration.json
@@ -3,55 +3,8 @@
"title": "Configuration",
"description": "Configuration for Maven plugin for Azure Web App",
"properties": {
- "subscriptionId": {
- "$ref": "#/definitions/non-empty-string"
- },
- "resourceGroup": {
- "$ref": "#/definitions/azure-resource-group"
- },
- "appName": {
- "type": "string",
- "pattern": "^[a-zA-Z0-9\\-]+$",
- "minLength": 2,
- "maxLength": 60
- },
- "appServicePlanName": {
- "type": "string",
- "pattern": "^[a-zA-Z0-9\\-]+$",
- "minLength": 1,
- "maxLength": 40
- },
- "appServicePlanResourceGroup": {
- "$ref": "#/definitions/azure-resource-group"
- },
- "auth": {
- "$ref": "#/definitions/auth"
- },
- "region": {
- "$ref": "#/definitions/non-empty-string"
- },
"pricingTier": {
- "$ref": "#/definitions/non-empty-string"
- },
- "runtime": {
- "$ref": "#/definitions/runtime"
- },
- "deployment": {
- "$ref": "#/definitions/deployment"
- },
- "deploymentSlot": {
- "$ref": "#/definitions/deployment-slot"
- },
- "appSettings": {
- "type": "object"
- },
- "allowTelemetry": {
- "type": "boolean",
- "default": true
- },
- "failsOnError": {
- "type": "boolean",
- "default": true
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
},
"stopAppDuringDeployment": {
"type": "boolean",
@@ -61,208 +14,26 @@
"type": "boolean",
"default": false
},
- "authType": {
- "$ref": "#/definitions/auth-type",
- "deprecationMessage": "Please set auth related properties like type in "
- }
- },
- "required": [
- "appName",
- "resourceGroup"
- ],
- "definitions": {
- "non-empty-string": {
- "type": "string",
- "minLength": 1
- },
- "auth-type": {
- "type": "string",
- "pattern": "(?i)^(auto|service_principal|managed_identity|azure_cli|vscode|intellij|azure_auth_maven_plugin|device_code|oauth2|visual_studio)$"
+ "region": {
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
},
- "azure-resource-group": {
+ "schemaVersion": {
"type": "string",
- "pattern": "^[a-zA-Z0-9._\\-()]+$",
- "minLength": 1,
- "maxLength": 90
- },
- "deployment-slot": {
- "title": "DeploymentSlotConfiguration",
- "description": "Deployment slot configuration for Maven plugin for Azure Web App",
- "type": "object",
- "properties": {
- "name": {
- "type": "string",
- "pattern": "^[A-Za-z0-9-]+$",
- "minLength": 1,
- "maxLength": 60
- },
- "configurationSource": {
- "$ref": "#/definitions/non-empty-string"
- }
- },
- "required": [
- "name"
- ]
+ "deprecationMessage": " has been deprecated, only v2 schema is supported now"
},
"runtime": {
- "title": "Runtime",
- "description": "Runtime configuration for Maven plugin for Azure Web App",
- "type": "object",
- "properties": {
- "os": {
- "description": "The operating system for app service",
- "type": "string",
- "pattern": "(?i)^(windows|linux|docker)$"
- },
- "webContainer": {
- "$ref": "#/definitions/non-empty-string"
- },
- "javaVersion": {
- "$ref": "#/definitions/non-empty-string"
- },
- "image": {
- "$ref": "#/definitions/non-empty-string"
- },
- "serverId": {
- "$ref": "#/definitions/non-empty-string"
- },
- "registryUrl": {
- "type": "string",
- "pattern": "^https.*"
- }
- },
- "dependencies": {
- "serverId": [
- "image"
- ],
- "registryUrl": [
- "image"
- ]
- },
- "required": [
- "os"
- ],
- "allOf": [
- {
- "if": {
- "properties": {
- "os": {
- "pattern": "(?i)^(windows|linux)$"
- }
- },
- "required": [
- "os"
- ]
- },
- "then": {
- "required": [
- "javaVersion",
- "webContainer"
- ]
- }
- },
- {
- "if": {
- "properties": {
- "os": {
- "pattern": "(?i)^(docker)$"
- }
- },
- "required": [
- "os"
- ]
- },
- "then": {
- "required": [
- "image"
- ]
- }
- }
- ]
- },
- "auth": {
- "title": "AuthConfiguration",
- "description": "The auth config for accessing azure resources",
- "type": "object",
- "properties": {
- "type": {
- "$ref": "#/definitions/auth-type"
- },
- "serverId": {
- "description": "The server id defined in maven settings",
- "type": "string"
- },
- "client": {
- "description": "Client ID",
- "type": "string"
- },
- "tenant": {
- "description": "Tenant ID",
- "type": "string"
- },
- "key": {
- "description": "Password",
- "type": "string"
- },
- "certificate": {
- "description": "The absolute path of your certificate",
- "type": "string"
- },
- "certificatePassword": {
- "description": "The password for your certificate, if there is any",
- "type": "string"
- },
- "environment": {
- "description": "The Azure cloud environment",
- "type": "string",
- "default": "AZURE",
- "pattern": "(?i)^(AZURE|AZURE_CHINA|AZURE_GERMANY|AZURE_US_GOVERNMENT)$"
- }
- },
- "allOf": [
- {
- "if": {
- "properties": {
- "type": {
- "pattern": "(?i)^service_principal$"
- }
- },
- "required": [
- "type"
- ]
- },
- "then": {
- "anyOf": [
- {
- "required": [
- "client",
- "tenant",
- "key"
- ]
- },
- {
- "required": [
- "client",
- "tenant",
- "certificate"
- ]
- }
- ]
- }
- }
- ],
- "not": {
- "required": [
- "key",
- "certificate"
- ]
- },
- "dependencies": {
- "certificatePassword": [
- "certificate"
- ]
- }
+ "$ref": "classpath:///schema/appservice/Runtime.json"
},
+ "deployment": {
+ "$ref": "#/definitions/deployment"
+ }
+ },
+ "allOf": [
+ {
+ "$ref": "classpath:///schema/maven/AzureAppServiceMavenPlugin.json"
+ }
+ ],
+ "definitions": {
"deployment-resource": {
"type": "object",
"title": "Deployment Resource",
@@ -273,21 +44,21 @@
"pattern": "(?i)^(war|jar|ear|lib|script|static|startup|zip)$"
},
"directory": {
- "$ref": "#/definitions/non-empty-string"
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
},
"targetPath": {
- "$ref": "#/definitions/non-empty-string"
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
},
"includes": {
"type": "array",
"items": {
- "$ref": "#/definitions/non-empty-string"
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
}
},
"excludes": {
"type": "array",
"items": {
- "$ref": "#/definitions/non-empty-string"
+ "$ref": "classpath:///schema/common/NonEmptyString.json"
}
}
}
diff --git a/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/DeployMojoTest.java b/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/DeployMojoTest.java
index ac30a368c0..79b9afeffe 100644
--- a/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/DeployMojoTest.java
+++ b/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/DeployMojoTest.java
@@ -94,7 +94,7 @@ public void getTelemetryProperties() throws Exception {
ReflectionUtils.setVariableValueInObject(spyMojo, "plugin", plugin);
doReturn("azure-webapp-maven-plugin").when(plugin).getArtifactId();
final Map map = spyMojo.getTelemetryProperties();
- assertEquals(12, map.size());
+ assertEquals(13, map.size());
assertTrue(map.containsKey(JAVA_VERSION_KEY));
assertTrue(map.containsKey(JAVA_WEB_CONTAINER_KEY));
assertTrue(map.containsKey(DOCKER_IMAGE_TYPE_KEY));
diff --git a/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/parser/ConfigParserTest.java b/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/parser/ConfigParserTest.java
index 3f9ce1fa03..784fab635d 100644
--- a/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/parser/ConfigParserTest.java
+++ b/azure-webapp-maven-plugin/src/test/java/com/microsoft/azure/maven/webapp/parser/ConfigParserTest.java
@@ -106,8 +106,8 @@ public void getWindowsRuntime() {
public void getLinuxRuntime() {
doReturn("linux").when(runtimeSetting).getOs();
doReturn("Java 8").when(runtimeSetting).getJavaVersion();
- doReturn("JBosseap 7.2").when(runtimeSetting).getWebContainer();
- assertEquals(parser.getRuntime(), Runtime.LINUX_JAVA8_JBOSS72);
+ doReturn("JBosseap 7").when(runtimeSetting).getWebContainer();
+ assertEquals(parser.getRuntime(), Runtime.LINUX_JAVA8_JBOSS7);
doReturn("linux").when(runtimeSetting).getOs();
doReturn("Java 11").when(runtimeSetting).getJavaVersion();
diff --git a/build-tools/pom.xml b/build-tools/pom.xml
index b2cfe02c71..c7f1b31307 100644
--- a/build-tools/pom.xml
+++ b/build-tools/pom.xml
@@ -7,7 +7,7 @@
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
maven-plugins-build-tools
diff --git a/build-tools/src/main/resources/checkstyle/checkstyle-suppressions.xml b/build-tools/src/main/resources/checkstyle/checkstyle-suppressions.xml
index 628f7bbf21..6303c32f8a 100644
--- a/build-tools/src/main/resources/checkstyle/checkstyle-suppressions.xml
+++ b/build-tools/src/main/resources/checkstyle/checkstyle-suppressions.xml
@@ -4,5 +4,6 @@
"https://checkstyle.org/dtds/suppressions_1_1.dtd">
-
+
+
diff --git a/build-tools/src/main/resources/checkstyle/checkstyle.xml b/build-tools/src/main/resources/checkstyle/checkstyle.xml
index a944eae803..6fd52915b5 100644
--- a/build-tools/src/main/resources/checkstyle/checkstyle.xml
+++ b/build-tools/src/main/resources/checkstyle/checkstyle.xml
@@ -10,7 +10,7 @@ page at https://checkstyle.org/config.html -->
-
+
@@ -26,17 +26,17 @@ page at https://checkstyle.org/config.html -->
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
@@ -51,19 +51,19 @@ page at https://checkstyle.org/config.html -->
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-->
-
+
@@ -212,7 +200,7 @@ page at https://checkstyle.org/config.html -->
-->
-
+
@@ -234,7 +222,7 @@ page at https://checkstyle.org/config.html -->
-->
-
+
@@ -268,7 +256,7 @@ page at https://checkstyle.org/config.html -->
+ value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
@@ -301,14 +289,15 @@ page at https://checkstyle.org/config.html -->
-
+
+
-
+
-
-
-
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
@@ -414,17 +403,47 @@ page at https://checkstyle.org/config.html -->
-
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index d59ad831ad..594b11929e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
com.microsoft.azure
azure-maven-plugins
- 1.14.0-SNAPSHOT
+ 1.14.0
pom
Maven Plugins for Azure
Maven plugins for Microsoft Azure services
@@ -80,8 +80,8 @@
3.1.0
2.9.1
3.1.2
-
- 1.14.0-SNAPSHOT
+ 1.12.6
+ 1.14.0
0.8.7
1.0.56
@@ -92,7 +92,7 @@
com.microsoft.azure
azure-toolkit-libs
- 0.11.0
+ 0.12.1
pom
import
@@ -191,6 +191,11 @@
+
+ com.nickwongdev
+ aspectj-maven-plugin
+ ${maven.aspectj-plugin.version}
+
maven-clean-plugin
${maven.clean-plugin.version}
@@ -253,7 +258,7 @@
com.microsoft.azure
maven-plugins-build-tools
- 1.14.0-SNAPSHOT
+ 1.14.0
com.puppycrawl.tools