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)
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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