88using System . Net . Http . Headers ;
99using System . Threading ;
1010using System . Threading . Tasks ;
11+ using Azure . Core ;
1112using Azure . Functions . Cli . Actions . LocalActions ;
12- using Azure . Functions . Cli . Arm . Models ;
1313using Azure . Functions . Cli . Common ;
14- using Azure . Functions . Cli . Diagnostics ;
1514using Azure . Functions . Cli . Extensions ;
1615using Azure . Functions . Cli . Helpers ;
1716using Azure . Functions . Cli . Interfaces ;
1817using Azure . Functions . Cli . StacksApi ;
1918using Colors . Net ;
2019using Fclp ;
21- using Microsoft . Build . Framework ;
2220using Microsoft . WindowsAzure . Storage ;
2321using Microsoft . WindowsAzure . Storage . Blob ;
2422using Newtonsoft . Json ;
25- using NuGet . Common ;
2623using static Azure . Functions . Cli . Common . OutputTheme ;
24+ using Site = Azure . Functions . Cli . Arm . Models . Site ;
2725
2826namespace Azure . Functions . Cli . Actions . AzureActions
2927{
@@ -34,7 +32,7 @@ internal class PublishFunctionAppAction : BaseFunctionAppAction
3432
3533 private readonly ISettings _settings ;
3634 private readonly ISecretsManager _secretsManager ;
37- private static string _requiredNetFrameworkVersion = "6 .0" ;
35+ private static string _requiredNetFrameworkVersion = "8 .0" ;
3836
3937 public bool PublishLocalSettings { get ; set ; }
4038 public bool OverwriteSettings { get ; set ; }
@@ -268,7 +266,14 @@ private async Task<IDictionary<string, string>> ValidateFunctionAppPublish(Site
268266 }
269267 }
270268
271- if ( functionApp . AzureAppSettings . TryGetValue ( Constants . FunctionsWorkerRuntime , out string workerRuntimeStr ) )
269+ string workerRuntimeStr = null ;
270+ if ( functionApp . IsFlex )
271+ {
272+ workerRuntimeStr = functionApp . FunctionAppConfig . runtime . name ;
273+ }
274+
275+ if ( ( functionApp . IsFlex && ! string . IsNullOrEmpty ( workerRuntimeStr ) ||
276+ ( ! functionApp . IsFlex && functionApp . AzureAppSettings . TryGetValue ( Constants . FunctionsWorkerRuntime , out workerRuntimeStr ) ) ) )
272277 {
273278 var resolution = $ "You can pass --force to update your Azure app with '{ workerRuntime } ' as a '{ Constants . FunctionsWorkerRuntime } '";
274279 try
@@ -312,7 +317,18 @@ private async Task<IDictionary<string, string>> ValidateFunctionAppPublish(Site
312317 throw new CliException ( $ "Azure Functions Core Tools does not support this deployment path. Please configure the app to deploy from a remote package using the steps here: https://aka.ms/deployfromurl") ;
313318 }
314319
315- await UpdateFrameworkVersions ( functionApp , workerRuntime , DotnetFrameworkVersion , Force , azureHelperService ) ;
320+ if ( functionApp . IsFlex )
321+ {
322+ if ( result . ContainsKey ( Constants . FunctionsWorkerRuntime ) )
323+ {
324+ await UpdateRuntimeConfigForFlex ( functionApp , WorkerRuntimeLanguageHelper . GetRuntimeMoniker ( workerRuntime ) , null , azureHelperService ) ;
325+ result . Remove ( Constants . FunctionsWorkerRuntime ) ;
326+ }
327+ }
328+ else
329+ {
330+ await UpdateFrameworkVersions ( functionApp , workerRuntime , DotnetFrameworkVersion , Force , azureHelperService ) ;
331+ }
316332
317333 // Special checks for python dependencies
318334 if ( workerRuntime == WorkerRuntime . python )
@@ -321,10 +337,12 @@ private async Task<IDictionary<string, string>> ValidateFunctionAppPublish(Site
321337 await PythonHelpers . WarnIfAzureFunctionsWorkerInRequirementsTxt ( ) ;
322338 // Check if remote LinuxFxVersion exists and is different from local version
323339 var localVersion = await PythonHelpers . GetEnvironmentPythonVersion ( ) ;
324- if ( ! PythonHelpers . IsLinuxFxVersionRuntimeVersionMatched ( functionApp . LinuxFxVersion , localVersion . Major , localVersion . Minor ) )
340+
341+ if ( ( ! functionApp . IsFlex && ! PythonHelpers . IsLinuxFxVersionRuntimeVersionMatched ( functionApp . LinuxFxVersion , localVersion . Major , localVersion . Minor ) ) ||
342+ ( functionApp . IsFlex && ! PythonHelpers . IsFlexPythonRuntimeVersionMatched ( functionApp . FunctionAppConfig ? . runtime ? . name , functionApp . FunctionAppConfig ? . runtime ? . version , localVersion . Major , localVersion . Minor ) ) )
325343 {
326344 ColoredConsole . WriteLine ( WarningColor ( $ "Local python version '{ localVersion . Version } ' is different from the version expected for your deployed Function App." +
327- $ " This may result in 'ModuleNotFound' errors in Azure Functions. Please create a Python Function App for version { localVersion . Major } .{ localVersion . Minor } or change the virtual environment on your local machine to match '{ functionApp . LinuxFxVersion } '.") ) ;
345+ $ " This may result in 'ModuleNotFound' errors in Azure Functions. Please create a Python Function App for version { localVersion . Major } .{ localVersion . Minor } or change the virtual environment on your local machine to match '{ ( functionApp . IsFlex ? functionApp . FunctionAppConfig . runtime . version : functionApp . LinuxFxVersion ) } '.") ) ;
328346 }
329347 }
330348
@@ -336,6 +354,59 @@ private async Task<IDictionary<string, string>> ValidateFunctionAppPublish(Site
336354 return result ;
337355 }
338356
357+ public static async Task UpdateRuntimeConfigForFlex ( Site site , string runtimeName , string runtimeVersion , AzureHelperService helperService )
358+ {
359+ if ( string . IsNullOrEmpty ( runtimeName ) )
360+ {
361+ return ;
362+ }
363+
364+ if ( string . IsNullOrEmpty ( runtimeVersion ) )
365+ {
366+ if ( runtimeName . Equals ( "python" , StringComparison . OrdinalIgnoreCase ) )
367+ {
368+ var localVersion = await PythonHelpers . GetEnvironmentPythonVersion ( ) ;
369+ runtimeVersion = $ "{ localVersion . Major } .{ localVersion . Minor } ";
370+ if ( runtimeVersion != "3.10" && runtimeVersion != "3.11" )
371+ {
372+ // todo: default will be 3.11 after 3.11 support is added.
373+ runtimeVersion = "3.10" ;
374+ }
375+ }
376+ else if ( runtimeName . Equals ( "dotnet-isolated" , StringComparison . OrdinalIgnoreCase ) )
377+ {
378+ // Only .NET 8.0 is supported in flex.
379+ if ( runtimeVersion != "8.0" )
380+ runtimeVersion = "8.0" ;
381+ }
382+ else if ( runtimeName . Equals ( "node" , StringComparison . OrdinalIgnoreCase ) )
383+ {
384+ // Only Node 18 is supported.
385+ if ( runtimeVersion != "18" )
386+ runtimeVersion = "18" ;
387+ }
388+ else if ( runtimeName . Equals ( "powershell" , StringComparison . OrdinalIgnoreCase ) )
389+ {
390+ // Only Python 7.2 is supported.
391+ if ( runtimeVersion != "7.2" )
392+ runtimeVersion = "7.2" ;
393+ }
394+ else if ( runtimeName . Equals ( "java" , StringComparison . OrdinalIgnoreCase ) )
395+ {
396+ // Warning: Java is not supported by core tools at the moment.
397+ ColoredConsole . WriteLine ( WarningColor ( $ "Java is not supported in core tools at the moment. Please use az cli to update the runtime information.") ) ;
398+ }
399+ else
400+ {
401+ // Warning: Runtime name is unknown.
402+ ColoredConsole . WriteLine ( WarningColor ( $ "Runtime is not updated. Only dotnet-isolated, node, java, and powershell is supported in core tools for Flex SKU.") ) ;
403+ return ;
404+ }
405+ }
406+
407+ await helperService . UpdateFlexRuntime ( site , runtimeName , runtimeVersion ) ;
408+ }
409+
339410 internal static async Task UpdateFrameworkVersions ( Site functionApp , WorkerRuntime workerRuntime , string requestedDotNetVersion , bool force , AzureHelperService helperService )
340411 {
341412 if ( workerRuntime == WorkerRuntime . dotnetIsolated )
@@ -686,6 +757,14 @@ await WaitForAppSettingUpdateSCM(functionApp, shouldHaveSettings: functionApp.Az
686757 /// <returns>ShouldSyncTrigger value</returns>
687758 private async Task < bool > HandleFlexConsumptionPublish ( Site functionApp , Func < Task < Stream > > zipFileFactory )
688759 {
760+ // Get the WorkerRuntime
761+ var workerRuntime = GlobalCoreToolsSettings . CurrentWorkerRuntime ;
762+
763+ if ( workerRuntime == WorkerRuntime . dotnetIsolated && _requiredNetFrameworkVersion != "8.0" )
764+ {
765+ throw new CliException ( $ "You are deploying .NET Isolated { _requiredNetFrameworkVersion } to Flex consumption. Flex consumpton only supports .NET 8. Please upgrade your app to .NET 8 and try the deployment again.") ;
766+ }
767+
689768 Task < DeployStatus > pollDeploymentStatusTask ( HttpClient client ) => KuduLiteDeploymentHelpers . WaitForFlexDeployment ( client , functionApp ) ;
690769 var deploymentParameters = new Dictionary < string , string > ( ) ;
691770
@@ -704,7 +783,7 @@ public async Task<DeployStatus> PerformFlexDeployment(Site functionApp, Func<Tas
704783 using ( var handler = new ProgressMessageHandler ( new HttpClientHandler ( ) ) )
705784 using ( var client = GetRemoteZipClient ( functionApp , handler ) )
706785 using ( var request = new HttpRequestMessage ( HttpMethod . Post , new Uri (
707- $ "api/Deploy/Zip ?isAsync=true&author={ Environment . MachineName } &Deployer=core_tools&{ string . Join ( "&" , deploymentParameters ? . Select ( kvp => $ "{ kvp . Key } ={ kvp . Value } ") ) ?? string . Empty } ", UriKind . Relative ) ) )
786+ $ "api/publish ?isAsync=true&author={ Environment . MachineName } &Deployer=core_tools&{ string . Join ( "&" , deploymentParameters ? . Select ( kvp => $ "{ kvp . Key } ={ kvp . Value } ") ) ?? string . Empty } ", UriKind . Relative ) ) )
708787 {
709788 ColoredConsole . WriteLine ( GetLogMessage ( "Creating archive for current directory..." ) ) ;
710789
@@ -1141,7 +1220,29 @@ private async Task<bool> PublishLocalAppSettings(Site functionApp, IDictionary<s
11411220
11421221 private async Task < bool > PublishAppSettings ( Site functionApp , IDictionary < string , string > local , IDictionary < string , string > additional )
11431222 {
1223+ string flexRuntimeName = null ;
1224+ string flexRuntimeVersion = null ;
1225+ if ( functionApp . IsFlex )
1226+ {
1227+ // if the additiona keys has runtime, it would mean that runtime is already updated.
1228+ if ( ! additional . ContainsKey ( Constants . FunctionsWorkerRuntime ) )
1229+ {
1230+ if ( local . ContainsKey ( Constants . FunctionsWorkerRuntime ) )
1231+ {
1232+ flexRuntimeName = local [ Constants . FunctionsWorkerRuntime ] ;
1233+ local . Remove ( Constants . FunctionsWorkerRuntime ) ;
1234+ }
1235+
1236+ if ( local . ContainsKey ( Constants . FunctionsWorkerRuntimeVersion ) )
1237+ {
1238+ flexRuntimeVersion = local [ Constants . FunctionsWorkerRuntimeVersion ] ;
1239+ local . Remove ( Constants . FunctionsWorkerRuntimeVersion ) ;
1240+ }
1241+ }
1242+ }
1243+
11441244 functionApp . AzureAppSettings = MergeAppSettings ( functionApp . AzureAppSettings , local , additional ) ;
1245+
11451246 var result = await AzureHelper . UpdateFunctionAppAppSettings ( functionApp , AccessToken , ManagementURL ) ;
11461247 if ( ! result . IsSuccessful )
11471248 {
@@ -1151,6 +1252,12 @@ private async Task<bool> PublishAppSettings(Site functionApp, IDictionary<string
11511252 . WriteLine ( ErrorColor ( result . ErrorResult ) ) ;
11521253 return false ;
11531254 }
1255+
1256+ if ( functionApp . IsFlex && ! string . IsNullOrEmpty ( flexRuntimeName ) )
1257+ {
1258+ await UpdateRuntimeConfigForFlex ( functionApp , flexRuntimeName , flexRuntimeVersion , new AzureHelperService ( AccessToken , ManagementURL ) ) ;
1259+ }
1260+
11541261 return true ;
11551262 }
11561263
@@ -1288,6 +1395,9 @@ public AzureHelperService(string accessToken, string managementUrl)
12881395
12891396 public virtual Task < HttpResult < string , string > > UpdateWebSettings ( Site functionApp , Dictionary < string , string > updatedSettings ) =>
12901397 AzureHelper . UpdateWebSettings ( functionApp , updatedSettings , _accessToken , _managementUrl ) ;
1398+
1399+ public virtual Task UpdateFlexRuntime ( Site functionApp , string runtimeName , string runtimeVersion ) =>
1400+ AzureHelper . UpdateFlexRuntime ( functionApp , runtimeName , runtimeVersion , _accessToken , _managementUrl ) ;
12911401 }
12921402
12931403 private void ShowEolMessage ( FunctionsStacks stacks , WindowsRuntimeSettings currentRuntimeSettings , int ? majorDotnetVersion )
0 commit comments