Skip to content

Commit c9af1d7

Browse files
authored
[App Service] Fix #21168: az webapp deploy: Call OneDeploy through ARM proxy if --src-url is provided (#26620)
1 parent 7015331 commit c9af1d7

6 files changed

Lines changed: 1939 additions & 1128 deletions

File tree

src/azure-cli/azure/cli/command_modules/appservice/_params.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -700,15 +700,16 @@ def load_arguments(self, _):
700700

701701
with self.argument_context('webapp deploy') as c:
702702
c.argument('name', options_list=['--name', '-n'], help='Name of the webapp to deploy to.')
703-
c.argument('src_path', options_list=['--src-path'], help='Path of the artifact to be deployed. Ex: "myapp.zip" or "/myworkspace/apps/myapp.war"')
704-
c.argument('src_url', options_list=['--src-url'], help='URL of the artifact. The webapp will pull the artifact from this URL. Ex: "http://mysite.com/files/myapp.war?key=123"')
705-
c.argument('target_path', options_list=['--target-path'], help='Absolute path that the artifact should be deployed to. Defaults to "home/site/wwwroot/" Ex: "/home/site/deployments/tools/", "/home/site/scripts/startup-script.sh".')
703+
c.argument('src_path', help='Path of the artifact to be deployed. Ex: "myapp.zip" or "/myworkspace/apps/myapp.war"')
704+
c.argument('src_url', help='URL of the artifact. The webapp will pull the artifact from this URL. Ex: "http://mysite.com/files/myapp.war?key=123"')
705+
c.argument('target_path', help='Absolute path that the artifact should be deployed to. Defaults to "home/site/wwwroot/" Ex: "/home/site/deployments/tools/", "/home/site/scripts/startup-script.sh".')
706706
c.argument('artifact_type', options_list=['--type'], help='Used to override the type of artifact being deployed.', choices=['war', 'jar', 'ear', 'lib', 'startup', 'static', 'zip'])
707-
c.argument('is_async', options_list=['--async'], help='If true, the artifact is deployed asynchronously. (The command will exit once the artifact is pushed to the web app.)', choices=['true', 'false'])
708-
c.argument('restart', options_list=['--restart'], help='If true, the web app will be restarted following the deployment. Set this to false if you are deploying multiple artifacts and do not want to restart the site on the earlier deployments.', choices=['true', 'false'])
709-
c.argument('clean', options_list=['--clean'], help='If true, cleans the target directory prior to deploying the file(s). Default value is determined based on artifact type.', choices=['true', 'false'])
710-
c.argument('ignore_stack', options_list=['--ignore-stack'], help='If true, any stack-specific defaults are ignored.', choices=['true', 'false'])
711-
c.argument('timeout', options_list=['--timeout'], help='Timeout for the deployment operation in milliseconds.')
707+
c.argument('is_async', options_list=['--async'], help='If true, the artifact is deployed asynchronously. (The command will exit once the artifact is pushed to the web app.). Synchronous deployments are not yet supported when using "--src-url"', arg_type=get_three_state_flag())
708+
c.argument('restart', help='If true, the web app will be restarted following the deployment. Set this to false if you are deploying multiple artifacts and do not want to restart the site on the earlier deployments.', arg_type=get_three_state_flag())
709+
c.argument('clean', help='If true, cleans the target directory prior to deploying the file(s). Default value is determined based on artifact type.', arg_type=get_three_state_flag())
710+
c.argument('ignore_stack', help='If true, any stack-specific defaults are ignored.', arg_type=get_three_state_flag())
711+
c.argument('reset', help='Reset Java apps to the default parking page if set to true with no type specified.', arg_type=get_three_state_flag())
712+
c.argument('timeout', type=int, help='Timeout for the deployment operation in milliseconds. Ignored when using "--src-url" since synchronous deployments are not yet supported when using "--src-url"')
712713
c.argument('slot', help="The name of the slot. Default to the productions slot if not specified.")
713714

714715
with self.argument_context('functionapp deploy') as c:

src/azure-cli/azure/cli/command_modules/appservice/custom.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5004,6 +5004,12 @@ def __init__(self):
50045004

50055005

50065006
def _build_onedeploy_url(params):
5007+
if params.src_url:
5008+
return _build_onedeploy_arm_url(params)
5009+
return _build_onedeploy_scm_url(params)
5010+
5011+
5012+
def _build_onedeploy_scm_url(params):
50075013
scm_url = _get_scm_url(params.cmd, params.resource_group_name, params.webapp_name, params.slot)
50085014
deploy_url = scm_url + '/api/publish?type=' + params.artifact_type
50095015

@@ -5025,6 +5031,24 @@ def _build_onedeploy_url(params):
50255031
return deploy_url
50265032

50275033

5034+
def _build_onedeploy_arm_url(params):
5035+
from azure.cli.core.commands.client_factory import get_subscription_id
5036+
client = web_client_factory(params.cmd.cli_ctx)
5037+
sub_id = get_subscription_id(params.cmd.cli_ctx)
5038+
if not params.slot:
5039+
base_url = (
5040+
f"subscriptions/{sub_id}/resourceGroups/{params.resource_group_name}/providers/Microsoft.Web/sites/"
5041+
f"{params.webapp_name}/extensions/onedeploy?api-version={client.DEFAULT_API_VERSION}"
5042+
)
5043+
else:
5044+
base_url = (
5045+
f"subscriptions/{sub_id}/resourceGroups/{params.resource_group_name}/providers/Microsoft.Web/sites/"
5046+
f"{params.webapp_name}/slots/{params.slot}/extensions/onedeploy"
5047+
f"?api-version={client.DEFAULT_API_VERSION}"
5048+
)
5049+
return params.cmd.cli_ctx.cloud.endpoints.resource_manager + base_url
5050+
5051+
50285052
def _get_ondeploy_headers(params):
50295053
if params.src_path:
50305054
content_type = 'application/octet-stream'
@@ -5057,9 +5081,18 @@ def _get_onedeploy_request_body(params):
50575081
"access it".format(params.src_path)) from e
50585082
elif params.src_url:
50595083
logger.info('Deploying from URL: %s', params.src_url)
5060-
body = json.dumps({
5061-
"packageUri": params.src_url
5062-
})
5084+
body = {
5085+
"properties": {
5086+
"packageUri": params.src_url,
5087+
"type": params.artifact_type,
5088+
"path": params.target_path,
5089+
"ignorestack": params.should_ignore_stack,
5090+
"clean": params.is_clean_deployment,
5091+
"restart": params.should_restart,
5092+
}
5093+
}
5094+
body = {"properties": {k: v for k, v in body["properties"].items() if v is not None}}
5095+
body = json.dumps(body)
50635096
else:
50645097
raise ResourceNotFoundError('Unable to determine source location of the artifact being deployed')
50655098

@@ -5095,12 +5128,15 @@ def _make_onedeploy_request(params):
50955128
deployment_status_url = _get_onedeploy_status_url(params)
50965129
headers = _get_ondeploy_headers(params)
50975130

5098-
logger.info("Deployment API: %s", deploy_url)
5099-
response = requests.post(deploy_url, data=body, headers=headers, verify=not should_disable_connection_verify())
5100-
51015131
# For debugging purposes only, you can change the async deployment into a sync deployment by polling the API status
51025132
# For that, set poll_async_deployment_for_debugging=True
5103-
poll_async_deployment_for_debugging = True
5133+
logger.info("Deployment API: %s", deploy_url)
5134+
if not params.src_url: # use SCM endpoint
5135+
response = requests.post(deploy_url, data=body, headers=headers, verify=not should_disable_connection_verify())
5136+
poll_async_deployment_for_debugging = True
5137+
else:
5138+
response = send_raw_request(params.cmd.cli_ctx, "PUT", deploy_url, body=body)
5139+
poll_async_deployment_for_debugging = False
51045140

51055141
# check the status of async deployment
51065142
if response.status_code == 202 or response.status_code == 200:
@@ -5110,6 +5146,12 @@ def _make_onedeploy_request(params):
51105146
response_body = _check_zip_deployment_status(params.cmd, params.resource_group_name, params.webapp_name,
51115147
deployment_status_url, params.slot, params.timeout)
51125148
logger.info('Async deployment complete. Server response: %s', response_body)
5149+
else:
5150+
if 'application/json' in response.headers.get('content-type', ""):
5151+
state = response.json().get("properties", {}).get("provisioningState")
5152+
if state:
5153+
logger.warning("Deployment status is: \"%s\"", state)
5154+
response_body = response.json().get("properties", {})
51135155
return response_body
51145156

51155157
# API not available yet!

0 commit comments

Comments
 (0)