def test_enable_zip_deploy_service_unavailable(self, requests_post_mock, get_scm_url_mock, get_site_credential_mock): # prepare cmd_mock = _get_test_cmd() cli_ctx_mock = mock.MagicMock() cmd_mock.cli_ctx = cli_ctx_mock response = mock.MagicMock() response.status_code = 503 requests_post_mock.return_value = response expected_zip_deploy_headers = _get_zip_deploy_headers( 'usr', 'pwd', cmd_mock.cli_ctx) # action with mock.patch('builtins.open', new_callable=mock.mock_open, read_data='zip-content'): with self.assertRaises(AzureInternalError): enable_zip_deploy(cmd_mock, 'rg', 'name', 'src', slot=None) # assert requests_post_mock.assert_called_with( 'https://mock-scm/api/zipdeploy?isAsync=true', data='zip-content', headers=expected_zip_deploy_headers, verify=mock.ANY)
def test_enable_zip_deploy_accepted(self, check_zip_deployment_status_mock, requests_post_mock, get_scm_url_mock, get_site_credential_mock): # prepare cmd_mock = _get_test_cmd() cli_ctx_mock = mock.MagicMock() cmd_mock.cli_ctx = cli_ctx_mock response = mock.MagicMock() response.status_code = 202 requests_post_mock.return_value = response expected_zip_deploy_headers = _get_zip_deploy_headers( 'usr', 'pwd', cmd_mock.cli_ctx) # action with mock.patch('builtins.open', new_callable=mock.mock_open, read_data='zip-content'): enable_zip_deploy(cmd_mock, 'rg', 'name', 'src', slot=None) # assert requests_post_mock.assert_called_with( 'https://mock-scm/api/zipdeploy?isAsync=true', data='zip-content', headers=expected_zip_deploy_headers, verify=mock.ANY) # TODO improve authorization matcher check_zip_deployment_status_mock.assert_called_with( cmd_mock, 'rg', 'name', 'https://mock-scm/api/deployments/latest', mock.ANY, None)
def test_enable_zip_deploy_remote_build_no_scm_site( self, get_scm_url_mock, get_site_credential_mock): # prepare cmd_mock = _get_test_cmd() cli_ctx_mock = mock.MagicMock() cmd_mock.cli_ctx = cli_ctx_mock # action # When the function app is created before 8/1/2019, it cannot use remote build with self.assertRaises(CLIError): enable_zip_deploy(cmd_mock, 'rg', 'name', 'src', slot=None) # assert get_site_credential_mock.assert_called_with(cmd_mock.cli_ctx, 'rg', 'name', None) get_scm_url_mock.assert_called_with(cmd_mock, 'rg', 'name', None)
def publish_app(cmd, resource_group_name, resource_name, git_url=None, git_token=None, git_branch='master', # pylint: disable=inconsistent-return-statements code_dir=None): # if given msbot json, use that to update environment settings like luis settings if git_url: return config_source_control( cmd=cmd, name=resource_name, resource_group_name=resource_group_name, repo_url=git_url, branch=git_branch, git_token=git_token ) # since there is no git url it's definitely publish from local if not code_dir: code_dir = os.getcwd() if code_dir: if not os.path.isdir(code_dir): raise CLIError('Please supply a valid directory path containing your source code') # ensure that the directory contains appropriate post deploy scripts folder if 'PostDeployScripts' not in os.listdir(code_dir): raise CLIError('Not a valid azure publish directory. missing post deploy scripts') shutil.make_archive('upload', 'zip', code_dir) output = enable_zip_deploy(cmd, resource_group_name, resource_name, 'upload.zip') os.remove('upload.zip') return output
def create_deploy_webapp(cmd, name, location=None, dryrun=False): import os 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") is_skip_build = language.lower() == STATIC_RUNTIME_NAME 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 \ version_used_create != "-" else 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_exists(cmd, 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.loads(dry_run_str) 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") return create_json # 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) # update create_json to include the app_url url = _get_app_url( cmd, rg_name, name) # picks the custom domain URL incase a domain is assigned if do_deployment: if not is_skip_build: # 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 _ping_scm_site(cmd, rg_name, name) 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("Preparing to deploy %s contents to app.", '' if is_skip_build else 'and build') enable_zip_deploy(cmd, rg_name, name, zip_file_path) # Remove the file afer deployment, handling exception if user removed the file manually try: os.remove(zip_file_path) except OSError: pass else: logger.warning( 'No known package (Node, ASP.NET, .NETCORE, or Static Html) ' 'found skipping zip and deploy process') create_json.update({'app_url': url}) logger.warning("All done.") return create_json
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 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