Skip to content

Commit

Permalink
Merge pull request #745 from JetBrains/develop.ra/deploy-web-app
Browse files Browse the repository at this point in the history
Rewrite web apps deploying
  • Loading branch information
rafaelldi authored Dec 19, 2023
2 parents 28880cf + c863454 commit 4552e0d
Show file tree
Hide file tree
Showing 30 changed files with 1,569 additions and 630 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
<actions implementation="com.microsoft.azure.toolkit.intellij.explorer.action.AzureExplorerActionsContributor"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<toolWindow anchor="left" id="Azure Explorer" canCloseContents="false" icon="/icons/Common/Azure.svg"
<toolWindow anchor="left" id="Azure Explorer" canCloseContents="false" icon="/icons/Rider/AzureToolWindow.svg"
factoryClass="com.microsoft.azure.toolkit.intellij.explorer.AzureExplorer$ToolWindowFactory"/>
</extensions>
<actions>
<action class="com.microsoft.azure.toolkit.intellij.explorer.action.AzureExplorerOpenAction" id="Actions.AzureExplorerOpenAction"
text="Show Azure Explorer" description="Show Azure Explorer" icon="/icons/Common/Azure.svg"/>
text="Show Azure Explorer" description="Show Azure Explorer" icon="/icons/Rider/AzureToolWindow.svg"/>
</actions>
</idea-plugin>
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
* Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.appservice.webapp

import com.microsoft.azure.toolkit.lib.Azure
import com.microsoft.azure.toolkit.lib.appservice.AzureAppService
import com.microsoft.azure.toolkit.lib.appservice.model.DockerConfiguration
import com.microsoft.azure.toolkit.lib.appservice.plan.AppServicePlanDraft
import com.microsoft.azure.toolkit.lib.appservice.webapp.*
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.task.AzureTask
import com.microsoft.azure.toolkit.lib.resource.task.CreateResourceGroupTask

class CreateOrUpdateDotNetWebAppTask(private val config: DotNetAppServiceConfig) : AzureTask<WebAppBase<*, *, *>>() {
private val subTasks: List<AzureTask<*>>

init {
subTasks = initTasks()
}

private fun initTasks(): List<AzureTask<*>> = listOf(
AzureTask(AzureString.format("Create new web app({0})", config.appName()), ::createOrUpdateResource)
)

private fun createOrUpdateResource(): WebAppBase<*, *, *> {
val az = Azure.az(AzureWebApp::class.java)
val target = az.webApps(config.subscriptionId()).getOrDraft(config.appName(), config.resourceGroup())
if (!isDeployToDeploymentSlot()) {
if (!target.exists()) {
val availability = az.get(config.subscriptionId(), null)?.checkNameAvailability(config.appName())
if (availability?.isAvailable != true) {
throw AzureToolkitRuntimeException(
AzureString.format(
"Cannot create webapp {0} due to error: {1}",
config.appName(),
availability?.unavailabilityReason
).string
)
}
return create()
} else {
return update(target)
}
} else {
if (!target.exists()) {
throw AzureToolkitRuntimeException("Target Web App does not exist. Please make sure the Web App name is correct")
}

val slotDraft = target.slots()
.updateOrCreate<WebAppDeploymentSlotDraft>(config.deploymentSlotName(), config.resourceGroup())
.toDotNetWebAppDeploymentSlotDraft()
val slotExists = slotDraft.exists()

return if (slotExists) updateDeploymentSlot(slotDraft)
else createDeploymentSlot(slotDraft)
}
}

private fun create(): WebApp {
CreateResourceGroupTask(config.subscriptionId(), config.resourceGroup(), config.region()).doExecute()

val planConfig = config.servicePlanConfig
val planDraft = Azure.az(AzureAppService::class.java)
.plans(planConfig.subscriptionId)
.updateOrCreate<AppServicePlanDraft>(planConfig.name, planConfig.resourceGroupName)
planDraft.planConfig = planConfig

val appDraft = Azure.az(AzureWebApp::class.java)
.webApps(config.subscriptionId())
.create<WebAppDraft>(config.appName(), config.resourceGroup())
.toDotNetWebAppDraft()

appDraft.appServicePlan = planDraft.commit()
appDraft.dotNetRuntime = getRuntime(config.dotnetRuntime)
appDraft.dockerConfiguration = getDockerConfiguration(config.dotnetRuntime)
appDraft.diagnosticConfig = config.diagnosticConfig()
appDraft.appSettings = config.appSettings()
appDraft.appSettingsToRemove = config.appSettingsToRemove()

return appDraft.createIfNotExist()
}

private fun update(webApp: WebApp): WebApp {
val planConfig = config.servicePlanConfig
val planDraft = Azure.az(AzureAppService::class.java)
.plans(planConfig.subscriptionId)
.updateOrCreate<AppServicePlanDraft>(planConfig.name, planConfig.resourceGroupName)
planDraft.planConfig = planConfig

val appDraft = (webApp.update() as WebAppDraft).toDotNetWebAppDraft()

appDraft.appServicePlan = planDraft.commit()
appDraft.dotNetRuntime = getRuntime(config.dotnetRuntime)
appDraft.dockerConfiguration = getDockerConfiguration(config.dotnetRuntime)
appDraft.diagnosticConfig = config.diagnosticConfig()
appDraft.appSettings = config.appSettings()
appDraft.appSettingsToRemove = config.appSettingsToRemove()

val result = appDraft.updateIfExist()
?: throw AzureToolkitRuntimeException("Unable to update Web App")

return result
}

private fun WebAppDraft.toDotNetWebAppDraft(): DotNetWebAppDraft {
val draftOrigin = origin
val draft =
if (draftOrigin != null) DotNetWebAppDraft(draftOrigin)
else DotNetWebAppDraft(name, resourceGroupName, module as WebAppModule)

return draft
}

private fun WebAppDeploymentSlotDraft.toDotNetWebAppDeploymentSlotDraft(): DotNetWebAppDeploymentSlotDraft{
val draftOrigin = origin
val draft =
if (draftOrigin != null) DotNetWebAppDeploymentSlotDraft(draftOrigin)
else DotNetWebAppDeploymentSlotDraft(name, module as WebAppDeploymentSlotModule)

return draft
}

private fun createDeploymentSlot(draft: DotNetWebAppDeploymentSlotDraft): WebAppDeploymentSlot {
draft.dotNetRuntime = getRuntime(config.dotnetRuntime)
draft.dockerConfiguration = getDockerConfiguration(config.dotnetRuntime)
draft.diagnosticConfig = config.diagnosticConfig()
draft.configurationSource = config.deploymentSlotConfigurationSource()
draft.appSettings = config.appSettings()
draft.appSettingsToRemove = config.appSettingsToRemove()

return draft.commit()
}

private fun updateDeploymentSlot(draft: DotNetWebAppDeploymentSlotDraft): WebAppDeploymentSlot {
draft.dotNetRuntime = getRuntime(config.dotnetRuntime)
draft.dockerConfiguration = getDockerConfiguration(config.dotnetRuntime)
draft.diagnosticConfig = config.diagnosticConfig()
draft.appSettings = config.appSettings()
draft.appSettingsToRemove = config.appSettingsToRemove()

return draft.commit()
}

private fun getRuntime(runtimeConfig: DotNetRuntimeConfig?): DotNetRuntime? {
if (runtimeConfig == null) return null

return if (!runtimeConfig.isDocker) {
DotNetRuntime(
runtimeConfig.os(),
runtimeConfig.stack,
runtimeConfig.frameworkVersion,
false
)
} else {
DotNetRuntime(
runtimeConfig.os(),
null,
null,
true
)
}
}

private fun getDockerConfiguration(runtimeConfig: DotNetRuntimeConfig?): DockerConfiguration? {
if (runtimeConfig == null || !runtimeConfig.isDocker) return null

return DockerConfiguration.builder()
.userName(runtimeConfig.username())
.password(runtimeConfig.password())
.registryUrl(runtimeConfig.registryUrl())
.image(runtimeConfig.image())
.startUpCommand(runtimeConfig.startUpCommand())
.build()
}

private fun isDeployToDeploymentSlot() = !config.deploymentSlotName().isNullOrEmpty()

override fun doExecute(): WebAppBase<*, *, *> {
var result: Any? = null
for (task in subTasks) {
try {
result = task.body.call()
} catch (e: Throwable) {
throw AzureToolkitRuntimeException(e)
}
}

return result as WebAppBase<*, *, *>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.appservice.webapp

import com.microsoft.azure.toolkit.lib.appservice.config.AppServiceConfig

class DotNetAppServiceConfig : AppServiceConfig() {
var dotnetRuntime: DotNetRuntimeConfig? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.appservice.webapp

import com.azure.resourcemanager.appservice.models.NetFrameworkVersion
import com.azure.resourcemanager.appservice.models.RuntimeStack
import com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem

data class DotNetRuntime(
val operatingSystem: OperatingSystem,
val stack: RuntimeStack?,
val frameworkVersion: NetFrameworkVersion?,
val isDocker: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.appservice.webapp

import com.azure.resourcemanager.appservice.models.NetFrameworkVersion
import com.azure.resourcemanager.appservice.models.RuntimeStack
import com.microsoft.azure.toolkit.lib.appservice.config.RuntimeConfig

class DotNetRuntimeConfig: RuntimeConfig() {
var isDocker: Boolean = false
var stack: RuntimeStack? = null
var frameworkVersion: NetFrameworkVersion? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license.
*/

package com.microsoft.azure.toolkit.intellij.appservice.webapp

import com.azure.resourcemanager.appservice.models.OperatingSystem
import com.azure.resourcemanager.appservice.models.RuntimeStack
import com.azure.resourcemanager.appservice.models.WebAppBase
import com.microsoft.azure.toolkit.lib.appservice.AppServiceAppBase

fun WebAppBase.getDotNetRuntime(): DotNetRuntime {
val os = operatingSystem()
if (os == OperatingSystem.LINUX) {
val stack = linuxFxVersion().substringBefore('|', "DOTNETCORE")
val version = linuxFxVersion().substringAfter('|', "8.0")
return DotNetRuntime(
com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem.LINUX,
RuntimeStack(stack, version),
null,
false
)
} else {
return DotNetRuntime(
com.microsoft.azure.toolkit.lib.appservice.model.OperatingSystem.WINDOWS,
null,
netFrameworkVersion(),
false
)
}
}

fun AppServiceAppBase<*, *, *>.getDotNetRuntime() = getRemote()?.getDotNetRuntime()
Loading

0 comments on commit 4552e0d

Please sign in to comment.