def download_app(cmd, client, resource_group_name, resource_name, file_save_path=None): # get the bot and ensure it's not a registration only bot raw_bot_properties = client.bots.get( resource_group_name=resource_group_name, resource_name=resource_name) if raw_bot_properties.kind == 'bot': raise CLIError( 'Source download is not supported for registration only bots') file_save_path = file_save_path or os.getcwd() if not os.path.isdir(file_save_path): raise CLIError('Path name not valid') folder_path = os.path.join(file_save_path, resource_name) if os.path.exists(folder_path): raise CLIError( 'The path {0} already exists. Please delete it or specify an alternate path' .format(folder_path)) os.mkdir(folder_path) user_name, password = _get_site_credential(cmd.cli_ctx, resource_group_name, resource_name, None) scm_url = _get_scm_url(cmd, resource_group_name, resource_name, None) import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) headers = authorization headers['content-type'] = 'application/json' payload = { 'command': 'PostDeployScripts\\prepareSrc.cmd {0}'.format(password), 'dir': r'site\wwwroot' } import requests response = requests.post(scm_url + '/api/command', data=json.dumps(payload), headers=headers) if response.status_code != 200: raise CLIError( 'Zip Download failed with status code {} and reason {}'.format( response.status_code, response.text)) response = requests.get(scm_url + '/api/vfs/site/bot-src.zip', headers=authorization) if response.status_code != 200: raise CLIError( 'Zip Download failed with status code {} and reason {}'.format( response.status_code, response.text)) download_path = os.path.join(file_save_path, 'download.zip') with open(os.path.join(file_save_path, 'download.zip'), 'wb') as f: f.write(response.content) import zipfile zip_ref = zipfile.ZipFile(download_path) zip_ref.extractall(folder_path) zip_ref.close() os.remove(download_path) return {'downloadPath': folder_path}
def _ping_scm_site(cmd, resource_group, name): # wakeup kudu, by making an SCM call import requests # work around until the timeout limits issue for linux is investigated & fixed user_name, password = _get_site_credential(cmd.cli_ctx, resource_group, name) scm_url = _get_scm_url(cmd, resource_group, name) import urllib3 authorization = urllib3.util.make_headers(basic_auth='{}:{}'.format(user_name, password)) requests.get(scm_url + '/api/settings', headers=authorization)
def start_scan(cmd, resource_group_name, name, timeout="", slot=None): webapp = show_webapp(cmd, resource_group_name, name, slot) is_linux = webapp.reserved if not is_linux: raise CLIError("Only Linux App Service Plans supported, Found a Windows App Service Plan") import requests user_name, password = _get_site_credential(cmd.cli_ctx, resource_group_name, name, slot) scm_url = _get_scm_url(cmd, resource_group_name, name, slot) start_scan_url = scm_url + '/api/scan/start/' + timeout import urllib3 authorization = urllib3.util.make_headers(basic_auth='{0}:{1}'.format(user_name, password)) headers = authorization headers['content-type'] = 'application/octet-stream' response = requests.get(start_scan_url, headers=authorization) return response.json()
def _build_onedeploy_url(params): scm_url = _get_scm_url(params.cmd, params.resource_group_name, params.webapp_name, params.slot) deploy_url = scm_url + '/api/publish?type=' + params.artifact_type if params.is_async_deployment is not None: deploy_url = deploy_url + '&async=' + str(params.is_async_deployment) if params.should_restart is not None: deploy_url = deploy_url + '&restart=' + str(params.should_restart) if params.is_clean_deployment is not None: deploy_url = deploy_url + '&clean=' + str(params.is_clean_deployment) if params.should_ignore_stack is not None: deploy_url = deploy_url + '&ignorestack=' + str( params.should_ignore_stack) if params.target_path is not None: deploy_url = deploy_url + '&path=' + params.target_path return deploy_url
def _zip_deploy(cmd, rg_name, name, zip_path): user_name, password = _get_site_credential(cmd.cli_ctx, rg_name, name) scm_url = _get_scm_url(cmd, rg_name, name) zip_url = scm_url + '/api/zipdeploy?isAsync=true' import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) headers = authorization headers['content-type'] = 'application/octet-stream' import requests import os # Read file content with open(os.path.realpath(os.path.expanduser(zip_path)), 'rb') as fs: zip_content = fs.read() requests.post(zip_url, data=zip_content, headers=headers) # keep checking for status of the deployment deployment_url = scm_url + '/api/deployments/latest' response = requests.get(deployment_url, headers=authorization) if response.json()['status'] != 4: logger.warning(response.json()['progress']) _check_deployment_status(deployment_url, authorization)
def enable_zip_deploy(cmd, resource_group_name, name, src, slot=None): user_name, password = _get_site_credential(cmd.cli_ctx, resource_group_name, name, slot) scm_url = _get_scm_url(cmd, resource_group_name, name, slot) zip_url = scm_url + '/api/zipdeploy?isAsync=true' deployment_status_url = scm_url + '/api/deployments/latest' import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) headers = authorization headers['content-type'] = 'application/octet-stream' import requests import os # Read file content with open(os.path.realpath(os.path.expanduser(src)), 'rb') as fs: zip_content = fs.read() requests.post(zip_url, data=zip_content, headers=headers) # check the status of async deployment try: from json.decoder import JSONDecodeError except ImportError: JSONDecodeError = ValueError response = requests.get(deployment_status_url, headers=authorization) try: response = response.json() if response.get('status', 0) != 4: logger.warning(response.get('progress', '')) response = _check_zip_deployment_status(deployment_status_url, authorization) return response except JSONDecodeError: logger.warning( """Unable to fetch status of deployment. Please check status manually using link '%s' """, deployment_status_url)
def create_deploy_webapp(cmd, name, location=None, dryrun=False): import os import json client = web_client_factory(cmd.cli_ctx) # the code to deploy is expected to be the current directory the command is running from src_dir = os.getcwd() # if dir is empty, show a message in dry run do_deployment = False if os.listdir(src_dir) == [] else True # determine the details for app to be created from src contents lang_details = get_lang_from_content(src_dir) # we support E2E create and deploy for Node & dotnetcore, any other stack, set defaults for os & runtime # and skip deployment if lang_details['language'] is None: do_deployment = False sku = 'F1' os_val = OS_DEFAULT detected_version = '-' runtime_version = '-' else: sku = lang_details.get("default_sku") language = lang_details.get("language") os_val = "Linux" if language.lower( ) == NODE_RUNTIME_NAME else OS_DEFAULT # detect the version data = get_runtime_version_details(lang_details.get('file_loc'), language) version_used_create = data.get('to_create') detected_version = data.get('detected') runtime_version = "{}|{}".format(language, version_used_create) if location is None: locs = client.list_geo_regions(sku, True) available_locs = [] for loc in locs: available_locs.append(loc.geo_region_name) location = available_locs[0] # Remove spaces from the location string, incase the GeoRegion string is used loc_name = location.replace(" ", "") full_sku = _get_sku_name(sku) is_linux = True if os_val == 'Linux' else False asp = "appsvc_asp_{}_{}".format(os_val, loc_name) rg_name = "appsvc_rg_{}_{}".format(os_val, loc_name) str_no_contents_warn = "" if not do_deployment: str_no_contents_warn = "[Empty directory, no deployment will be triggered]" # Resource group: check if default RG is set default_rg = cmd.cli_ctx.config.get('defaults', 'group', fallback=None) if default_rg and check_resource_group_supports_os(cmd, default_rg, location, is_linux): rg_name = default_rg rg_mssg = "[Using default Resource group]" else: rg_mssg = "" src_path = "{} {}".format(src_dir.replace("\\", "\\\\"), str_no_contents_warn) rg_str = "{} {}".format(rg_name, rg_mssg) dry_run_str = r""" { "name" : "%s", "serverfarm" : "%s", "resourcegroup" : "%s", "sku": "%s", "os": "%s", "location" : "%s", "src_path" : "%s", "version_detected": "%s", "version_to_create": "%s" } """ % (name, asp, rg_str, full_sku, os_val, location, src_path, detected_version, runtime_version) create_json = json.dumps(json.loads(dry_run_str), indent=4, sort_keys=True) if dryrun: logger.warning( "Web app will be created with the below configuration,re-run command " "without the --dryrun flag to create & deploy a new app") logger.warning(create_json) return None # create RG if the RG doesn't already exist if not check_resource_group_exists(cmd, rg_name): logger.warning("Creating Resource group '%s' ...", rg_name) create_resource_group(cmd, rg_name, location) logger.warning("Resource group creation complete") else: logger.warning("Resource group '%s' already exists.", rg_name) # create asp if not check_if_asp_exists(cmd, rg_name, asp): logger.warning("Creating App service plan '%s' ...", asp) sku_def = SkuDescription(tier=full_sku, name=sku, capacity=(1 if is_linux else None)) plan_def = AppServicePlan(loc_name, app_service_plan_name=asp, sku=sku_def, reserved=(is_linux or None)) client.app_service_plans.create_or_update(rg_name, asp, plan_def) logger.warning("App service plan creation complete") else: logger.warning("App service plan '%s' already exists.", asp) # create the app if not check_app_exists(cmd, rg_name, name): logger.warning("Creating app '%s' ....", name) create_webapp(cmd, rg_name, name, asp, runtime_version if is_linux else None) logger.warning("Webapp creation complete") else: logger.warning("App '%s' already exists", name) if do_deployment: # setting to build after deployment logger.warning( "Updating app settings to enable build after deployment") update_app_settings(cmd, rg_name, name, ["SCM_DO_BUILD_DURING_DEPLOYMENT=true"]) # work around until the timeout limits issue for linux is investigated & fixed # wakeup kudu, by making an SCM call import requests # work around until the timeout limits issue for linux is investigated & fixed user_name, password = _get_site_credential(cmd.cli_ctx, rg_name, name) scm_url = _get_scm_url(cmd, rg_name, name) import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) requests.get(scm_url + '/api/settings', headers=authorization) logger.warning("Creating zip with contents of dir %s ...", src_dir) # zip contents & deploy zip_file_path = zip_contents_from_dir(src_dir, language) logger.warning("Deploying and building contents to app." "This operation can take some time to finish...") enable_zip_deploy(cmd, rg_name, name, zip_file_path) else: logger.warning( "No 'NODE' or 'DOTNETCORE' package detected, skipping zip and deploy process" ) logger.warning("All done. %s", create_json) return None
def _get_onedeploy_status_url(params): scm_url = _get_scm_url(params.cmd, params.resource_group_name, params.webapp_name, params.slot) return scm_url + '/api/deployments/latest'
def create_deploy_webapp(cmd, name, location=None, dryrun=False): import os import json client = web_client_factory(cmd.cli_ctx) sku = "S1" os_val = "Linux" language = "node" full_sku = _get_sku_name(sku) if location is None: locs = client.list_geo_regions(sku, True) available_locs = [] for loc in locs: available_locs.append(loc.geo_region_name) location = available_locs[0] # Remove spaces from the location string, incase the GeoRegion string is used loc_name = location.replace(" ", "") asp = "appsvc_asp_{}_{}".format(os_val, loc_name) rg_name = "appsvc_rg_{}_{}".format(os_val, loc_name) # the code to deploy is expected to be the current directory the command is running from src_dir = os.getcwd() # if dir is empty, show a message in dry run do_deployment = False if os.listdir(src_dir) == [] else True package_json_path = is_node_application(src_dir) str_no_contents_warn = "" if not do_deployment: str_no_contents_warn = "[Empty directory, no deployment will be triggered]" if package_json_path == '': node_version = "[No package.json file found in root directory, not a Node app?]" version_used_create = "8.0" else: with open(package_json_path) as data_file: data = json.load(data_file) node_version = data['version'] version_used_create = get_node_runtime_version_toSet() # Resource group: check if default RG is set default_rg = cmd.cli_ctx.config.get('defaults', 'group', fallback=None) if default_rg and check_resource_group_supports_linux( cmd, default_rg, location): rg_name = default_rg rg_mssg = "[Using default Resource group]" else: rg_mssg = "" runtime_version = "{}|{}".format(language, version_used_create) src_path = "{} {}".format(src_dir.replace("\\", "\\\\"), str_no_contents_warn) rg_str = "{} {}".format(rg_name, rg_mssg) dry_run_str = r""" { "name" : "%s", "serverfarm" : "%s", "resourcegroup" : "%s", "sku": "%s", "os": "%s", "location" : "%s", "src_path" : "%s", "version_detected": "%s", "version_to_create": "%s" } """ % (name, asp, rg_str, full_sku, os_val, location, src_path, node_version, runtime_version) create_json = json.dumps(json.loads(dry_run_str), indent=4, sort_keys=True) if dryrun: logger.warning( "Web app will be created with the below configuration,re-run command " "without the --dryrun flag to create & deploy a new app") logger.warning(create_json) return None # create RG if the RG doesn't already exist if not check_resource_group_exists(cmd, rg_name): logger.warning("Creating Resource group '%s' ...", rg_name) create_resource_group(cmd, rg_name, location) logger.warning("Resource group creation complete") else: logger.warning("Resource group '%s' already exists.", rg_name) # create asp if not check_if_asp_exists(cmd, rg_name, asp): logger.warning("Creating App service plan '%s' ...", asp) sku_def = SkuDescription(tier=full_sku, name=sku, capacity=1) plan_def = AppServicePlan(loc_name, app_service_plan_name=asp, sku=sku_def, reserved=True) client.app_service_plans.create_or_update(rg_name, asp, plan_def) logger.warning("App service plan creation complete") else: logger.warning("App service plan '%s' already exists.", asp) # create the Linux app if not check_app_exists(cmd, rg_name, name): logger.warning("Creating app '%s' ....", name) create_webapp(cmd, rg_name, name, asp, runtime_version) logger.warning("Webapp creation complete") else: logger.warning("App '%s' already exists", name) # setting to build after deployment logger.warning("Updating app settings to enable build after deployment") update_app_settings(cmd, rg_name, name, ["SCM_DO_BUILD_DURING_DEPLOYMENT=true"]) # work around until the timeout limits issue for linux is investigated & fixed # wakeup kudu, by making an SCM call import requests # work around until the timeout limits issue for linux is investigated & fixed user_name, password = _get_site_credential(cmd.cli_ctx, rg_name, name) scm_url = _get_scm_url(cmd, rg_name, name) import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) requests.get(scm_url + '/api/settings', headers=authorization) if package_json_path != '': logger.warning("Creating zip with contents of dir %s ...", src_dir) # zip contents & deploy zip_file_path = zip_contents_from_dir(src_dir) logger.warning("Deploying and building contents to app." "This operation can take some time to finish...") enable_zip_deploy(cmd, rg_name, name, zip_file_path) else: logger.warning( "No package.json found, skipping zip and deploy process") logger.warning("All done. %s", create_json) return None
def enable_one_deploy(cmd, resource_group_name, name, src, deploy_type=None, is_async=None, target_path=None, timeout=None, slot=None): import ntpath logger.info("Preparing for deployment") user_name, password = _get_site_credential(cmd.cli_ctx, resource_group_name, name, slot) try: scm_url = _get_scm_url(cmd, resource_group_name, name, slot) except ValueError: raise CLIError('Failed to fetch scm url for for app {}'.format(name)) # Interpret deployment type from the file extension if the type parameter is not passed if deploy_type is None: fileName = ntpath.basename(src) fileExtension = fileName.split(".", 1)[1] if fileExtension in ('war', 'jar', 'zip', 'ear'): deploy_type = fileExtension elif fileExtension in ('sh', 'bat'): deploy_type = 'startup' else: deploy_type = 'static' logger.warning( "Deployment type: %s. To override deloyment type, please specify the --type parameter. Possible values: static, zip, war, jar, ear, startup", deploy_type) deploy_url = scm_url + '/api/publish?type=' + deploy_type if is_async is not None: deploy_url = deploy_url + '&async=true' if target_path is not None: deploy_url = deploy_url + '&path=' + target_path deployment_status_url = scm_url + '/api/deployments/latest' from azure.cli.core.util import (should_disable_connection_verify, get_az_user_agent) import urllib3 authorization = urllib3.util.make_headers( basic_auth='{0}:{1}'.format(user_name, password)) headers = authorization headers['Content-Type'] = 'application/octet-stream' headers['Cache-Control'] = 'no-cache' headers['User-Agent'] = get_az_user_agent() import requests import os # Read file content with open(os.path.realpath(os.path.expanduser(src)), 'rb') as fs: artifact_content = fs.read() logger.warning("Starting deployment...") res = requests.post(deploy_url, data=artifact_content, headers=headers, verify=not should_disable_connection_verify()) # check if an error occured during deployment if res.status_code == 400: raise CLIError("An error occured durng deployment: {}".format( res.text)) # check if there's an ongoing process if res.status_code == 409: raise CLIError( "There may be an ongoing deployment or your app setting has WEBSITE_RUN_FROM_PACKAGE. " "Please track your deployment in {} and ensure the WEBSITE_RUN_FROM_PACKAGE app setting " "is removed.".format(deployment_status_url)) # check the status of async deployment if res.status_code == 202: logger.warning("Asynchronous deployment request has been recieved") response = _check_zip_deployment_status(cmd, resource_group_name, name, deployment_status_url, authorization, timeout) return response return logger.warning("Deployment has completed successfully")