77import threading
88import time
99import re
10+ import requests
1011from xml .etree import ElementTree
1112
1213from urllib .parse import urlparse
9899from .aaz .latest .relay .hyco .authorization_rule .keys import List as HycoAuthoKeysList
99100from .aaz .latest .relay .namespace import List as NamespaceList
100101
102+
101103logger = get_logger (__name__ )
102104
103105# pylint:disable=no-member,too-many-lines,too-many-locals
@@ -791,6 +793,7 @@ def enable_zip_deploy(cmd, resource_group_name, name, src, timeout=None, slot=No
791793 from azure .cli .core .util import should_disable_connection_verify
792794 # check if the app is a linux web app
793795 app_is_linux_webapp = is_linux_webapp (app )
796+ app_is_function_app = is_functionapp (app )
794797
795798 # Read file content
796799 with open (os .path .realpath (os .path .expanduser (src )), 'rb' ) as fs :
@@ -799,7 +802,11 @@ def enable_zip_deploy(cmd, resource_group_name, name, src, timeout=None, slot=No
799802 if app_is_linux_webapp and track_status is not None and track_status :
800803 headers ["x-ms-artifact-checksum" ] = _compute_checksum (zip_content )
801804
802- res = requests .post (zip_url , data = zip_content , headers = headers , verify = not should_disable_connection_verify ())
805+ if app_is_linux_webapp and not app_is_function_app :
806+ cookie = _warmup_kudu_and_get_cookie_internal (cmd , resource_group_name , name , slot )
807+ res = requests .post (zip_url , data = zip_content , headers = headers , cookies = {cookie }, verify = not should_disable_connection_verify ())
808+ else :
809+ res = requests .post (zip_url , data = zip_content , headers = headers , verify = not should_disable_connection_verify ())
803810 logger .warning ("Deployment endpoint responded with status code %d" , res .status_code )
804811
805812 # check the status of async deployment
@@ -6981,6 +6988,9 @@ def perform_onedeploy_webapp(cmd,
69816988 params .slot = slot
69826989 params .track_status = track_status
69836990
6991+ client = web_client_factory (cmd .cli_ctx )
6992+ app = client .web_apps .get (resource_group_name , name )
6993+ params .is_linux_webapp = is_linux_webapp (app )
69846994 return _perform_onedeploy_internal (params )
69856995
69866996
@@ -7002,6 +7012,7 @@ def __init__(self):
70027012 self .timeout = None
70037013 self .slot = None
70047014 self .track_status = False
7015+ self .is_linux_webapp = False
70057016# pylint: enable=too-many-instance-attributes,too-few-public-methods
70067017
70077018
@@ -7050,6 +7061,24 @@ def _build_onedeploy_arm_url(params):
70507061 )
70517062 return params .cmd .cli_ctx .cloud .endpoints .resource_manager + base_url
70527063
7064+ def _build_get_instances_list_arm_url (params ):
7065+ from azure .cli .core .commands .client_factory import get_subscription_id
7066+ client = web_client_factory (params .cmd .cli_ctx )
7067+ sub_id = get_subscription_id (params .cmd .cli_ctx )
7068+ if not params .slot :
7069+ base_url = (
7070+ f"subscriptions/{ sub_id } /resourceGroups/{ params .resource_group_name } /providers/Microsoft.Web/sites/"
7071+ f"{ params .webapp_name } /instances?api-version={ client .DEFAULT_API_VERSION } "
7072+ )
7073+ else :
7074+ base_url = (
7075+ f"subscriptions/{ sub_id } /resourceGroups/{ params .resource_group_name } /providers/Microsoft.Web/sites/"
7076+ f"{ params .webapp_name } /slots/{ params .slot } /instances"
7077+ f"?api-version={ client .DEFAULT_API_VERSION } "
7078+ )
7079+
7080+ logger .info ("get instances list url: %s" , base_url )
7081+ return params .cmd .cli_ctx .cloud .endpoints .resource_manager + base_url
70537082
70547083def _build_deploymentstatus_url (cmd , resource_group_name , webapp_name , slot , deployment_id ):
70557084 from azure .cli .core .commands .client_factory import get_subscription_id
@@ -7143,6 +7172,52 @@ def _update_artifact_type(params):
71437172 logger .warning ("Deployment type: %s. To override deployment type, please specify the --type parameter. "
71447173 "Possible values: war, jar, ear, zip, startup, script, static" , params .artifact_type )
71457174
7175+ def _get_instances_list_arm_internal (params ):
7176+ url = _build_get_instances_list_arm_url (params )
7177+ response = send_raw_request (params .cmd .cli_ctx , "GET" , url )
7178+ if response .status_code == 200 :
7179+ logger .info ("Instances list retrieved successfully." )
7180+ return response .json ().get ("value" , [])
7181+ raise CLIError ("Unable to get instances list." )
7182+
7183+ def _get_instance_id_internal (param ):
7184+ instances = _get_instances_list_arm_internal (param )
7185+
7186+ if not instances or len (instances ) == 0 :
7187+ raise CLIError ("No instances found." )
7188+
7189+ logger .info ("returning instance id for instance: %s" , instances [0 ]['name' ])
7190+ return instances [0 ]['name' ]
7191+
7192+
7193+ def _get_affinity_cookie_internal (param ):
7194+ instance = _get_instance_id_internal (param )
7195+ logger .info ("returning affinity cookie for instance: %s" , instance )
7196+ cookie = {
7197+ "ARRAffinity" : instance ,
7198+ "ARRAffinitySameSite" : instance
7199+ }
7200+ return cookie
7201+
7202+ def _warmup_kudu_and_get_cookie_internal (param ):
7203+ scm_url = _get_scm_url (param .cmd , param .resource_group_name , param .webapp_name , param .slot )
7204+ cookie = _get_affinity_cookie_internal (param )
7205+ Max_Retries = 3
7206+ TimeOut = 300
7207+ SleepInterval = 60
7208+ for retry in range (Max_Retries ):
7209+ if _ping_kudu_internal (scm_url , param , cookie , TimeOut ):
7210+ logger .info ("Kudu warmed up successfully. Retry count: %d" , retry )
7211+ return cookie
7212+ time .sleep (SleepInterval )
7213+
7214+ raise CLIError ("Unable to warm up Kudu." )
7215+
7216+ def _ping_kudu_internal (scm_url , param , cookie , timeout ):
7217+ logger .info ("Warming up Kudu." )
7218+ headers = get_scm_site_headers (param .cmd .cli_ctx , param .webapp_name , param .resource_group_name )
7219+ response = requests .get (scm_url + '/deployments' , headers = headers , cookies = cookie , timeout = timeout )
7220+ return response .status_code == 200
71467221
71477222def _make_onedeploy_request (params ):
71487223 import requests
@@ -7161,7 +7236,13 @@ def _make_onedeploy_request(params):
71617236 # For that, set poll_async_deployment_for_debugging=True
71627237 logger .info ("Deployment API: %s" , deploy_url )
71637238 if not params .src_url : # use SCM endpoint
7164- response = requests .post (deploy_url , data = body , headers = headers , verify = not should_disable_connection_verify ())
7239+ # if linux webapp then warmup kudu and use warmed up kudu for deployment
7240+ if params .is_linux_webapp and not params .is_functionapp :
7241+ logger .info ("Warming up Kudu before deployment." )
7242+ cookies = _warmup_kudu_and_get_cookie_internal (params )
7243+ response = requests .post (deploy_url , data = body , headers = headers , cookies = cookies , verify = not should_disable_connection_verify ())
7244+ else :
7245+ response = requests .post (deploy_url , data = body , headers = headers , verify = not should_disable_connection_verify ())
71657246 poll_async_deployment_for_debugging = True
71667247 else :
71677248 response = send_raw_request (params .cmd .cli_ctx , "PUT" , deploy_url , body = body )
0 commit comments