コード例 #1
0
def run_safe_validations(handler):
    """This function runs all the validations that can safely be done without running
    user code. It returns the common parent directory of the archive.
    """
    logger.info(">> Running safe validations")
    # check archive format
    namelist = handler.get_namelist()
    common_dir = validate_archive_files(namelist)
    logger.debug("Common directory is %s" % common_dir)
    
    # check for and then read configuration file
    config_file = common_dir + os.sep + DJANGO_CFG_FILENAME
    if not handler.is_file_in_archive(config_file):
        raise FileMissingError("Archive missing configuration file %s" %
                               config_file)
    fileobj = handler.open_member(config_file)
    data = fileobj.read()
    django_config = django_config_from_json(data, COMPATIBLE_PACKAGER_VERSION)

    # check for additional_components file and parse if present
    components_file = common_dir + os.sep + COMPONENTS_FILENAME
    if handler.is_file_in_archive(components_file):
        fileobj = handler.open_member(components_file)
        read_components_file(fileobj, components_file, django_config.components)
    else:
        if len(django_config.components)>0:
            raise ValidationError("No additional component file at %s, but application with packaged with an additional component file" %
                                  filepath)

    # check for other required files
    settings_module_file = django_config.get_settings_module_file()
    if not handler.is_file_in_archive(settings_module_file):
        raise FileMissingError("Archive missing django settings file %s" % settings_module_file)
    logger.debug("Has required files")
    return (common_dir, django_config)
コード例 #2
0
def simulated_install(archive_file_or_directory,
                      install_path,
                      django_settings_module,
                      package_cache_dir=None):
    """Simulate the install process. install_path is the directory under
    which we extract the archive. We also create a python virtualenv there
    and install all the required dependencies.
    """
    if not os.path.isdir(install_path):
        raise Exception(
            "simulated_install: install_path %s does not exist" % install_path)
    if os.path.isdir(archive_file_or_directory):
        app_dir_path = os.path.join(
            install_path, os.path.basename(archive_file_or_directory))
        shutil.copytree(archive_file_or_directory, app_dir_path)
    else:  # we have an archive
        with create_handler(archive_file_or_directory) as h:
            common_dir = validate_archive_files(h.get_namelist())
            h.extract(install_path)
        app_dir_path = os.path.join(install_path, common_dir)
    components_file = os.path.join(app_dir_path, COMPONENTS_FILENAME)
    if os.path.exists(components_file):
        with open(components_file, "rb") as cf:
            components_list = read_components_file(cf, components_file, None)
    else:
        components_list = []
    undo_ops = generate_settings_file(app_dir_path, django_settings_module,
                                      components_list)
    virtualenv_path = os.path.join(install_path, "python")
    create_virtualenv(virtualenv_path, package_cache_dir=package_cache_dir)
    platform_reqs = write_platform_requirements_file(install_path,
                                                     components_list)
    logger.info(">> Installing platform requirements into virtualenv")
    install_requirements(
        virtualenv_path, platform_reqs, package_cache_dir=package_cache_dir)
    app_reqs = os.path.join(app_dir_path, "requirements.txt")
    if os.path.exists(app_reqs):
        logger.info(">> Installing application requirements into virtualenv")
        install_requirements(
            virtualenv_path, app_reqs, package_cache_dir=package_cache_dir)
    else:
        logger.debug("No install requirements file at %s" % app_reqs)
    return (app_dir_path, undo_ops, os.path.join(virtualenv_path,
                                                 "bin/python"))
コード例 #3
0
def validate_settings(app_dir_path, django_settings_module, django_config=None,
                      prev_version_component_list=None):
    """This is the main settings validation function. It takes the following arguments:
        app_dir_path           - path to the top level directory of the extracted application
        django_settings_module - fully qualified name of the django settings module
        django_config          - if provided, this is the django_config data generated
                                 during the original packaging of the app. We validate
                                 that it is still consistent with the current app.

    This function returns an intance of SettingValidationResults.

    Note that validate_settings() must be run after generate_settings(). We import
    the deployed_settings module rather than the user's django_settings_module so
    we can see whether they've overridden any of the settings.
    """
    # normalize the target install path
    app_dir_path = os.path.abspath(os.path.expanduser(app_dir_path))
    
    results = SettingValidationResults(VERSION, logger)
    python_path_dir = find_python_module(django_settings_module, app_dir_path)
    if not python_path_dir:
        raise ValidationError("Unable to find django settings module %s under %s" % (django_settings_module, app_dir_path))
    # we store only the subdirectory part of the python path, since the rest depends
    # on where we install the app.
    if os.path.dirname(app_dir_path)==python_path_dir:
        results.python_path_subdirectory = ""
    else:
        results.python_path_subdirectory = _get_subdir_component(os.path.dirname(app_dir_path), python_path_dir)
    # get the settings file directory
    settings_file_directory = get_settings_file_directory(python_path_dir, django_settings_module)

    # do the import of app's settings
    sys.path = [python_path_dir] + sys.path

    deployed_settings_module = get_deployed_settings_module(django_settings_module)
    logger.debug("Importing settings module %s" % deployed_settings_module)
    try:
        settings_module = import_module(deployed_settings_module)
    except:
        (exc_type, exc_value, exc_traceback) = sys.exc_info()
        logger.exception("Exception in settings file import: %s(%s)" %
                         (exc_type.__name__, str(exc_value)))
        raise SettingsImportError("Error in settings import: %s(%s)" %
                                  (exc_type.__name__, str(exc_value)))
        
    # Check that the settings controlled by engage weren't overridden by app.
    # If any are overridden, we treat them as warnings.
    check_if_setting_overridden('TIME_ZONE', settings_module, results)
    check_if_setting_overridden('SECRET_KEY', settings_module, results)
    check_if_setting_overridden('ADMINS', settings_module, results)
    check_if_setting_overridden('DATABASES', settings_module, results)
    check_if_setting_overridden('LOGGING_CONFIG', settings_module,
                                results)

    # Check that settings which point to a directory are either not set or
    # point to a valid directory
    if hasattr(settings_module, "MEDIA_ROOT"):
        check_directory_setting("MEDIA_ROOT",
                                settings_module.MEDIA_ROOT,
                                '', app_dir_path, results)
    if hasattr(settings_module, "TEMPLATE_DIRS"):
        check_directory_tuple_setting("TEMPLATE_DIRS",
                                      settings_module.TEMPLATE_DIRS,
                                      app_dir_path, results)
    
    # Get the packages in requirements.txt. We use this in validating
    # the django apps. We defer the validation of the actual packages
    # until we have parsed and validated the engage_components.json file.
    user_required_packages = get_user_required_packages(app_dir_path)
    
    # check that all INSTALLED_APPS are pointing to apps accessible in the target system
    if hasattr(settings_module, "INSTALLED_APPS"):
        installed_apps = []
        packages = PREINSTALLED_PACKAGES + user_required_packages
        known_apps = set(get_apps_for_packages(packages))
        for app_name in settings_module.INSTALLED_APPS:
            validate_installed_app(app_name, python_path_dir, known_apps,
                                   app_dir_path, django_settings_module, results)
            installed_apps.append(app_name)
    else:
        installed_apps = []
    results.installed_apps = installed_apps

    if hasattr(settings_module, "FIXTURE_DIRS"):
        fixture_dirs = _tuple_setting_to_list(settings_module.FIXTURE_DIRS)
        check_directory_tuple_setting("FIXTURE_DIRS", fixture_dirs,
                                      app_dir_path, results)
    else:
        fixture_dirs = []
    # check that ENGAGE_APP_DB_FIXTURES points to valid fixture files
    if hasattr(settings_module, "ENGAGE_APP_DB_FIXTURES"):
        results.fixtures = _tuple_setting_to_list(settings_module.ENGAGE_APP_DB_FIXTURES)
        for fixture in results.fixtures:
            validate_fixture_file(fixture, results.installed_apps, fixture_dirs,
                                  python_path_dir, settings_file_directory, known_apps, results)
    else:
        results.fixtures = []

    # check ENGAGE_MIGRATION_APPS, if present
    if hasattr(settings_module, "ENGAGE_MIGRATION_APPS"):
        results.migration_apps = _tuple_setting_to_list(settings_module.ENGAGE_MIGRATION_APPS)
        if len(results.migration_apps)>0 and not ("south" in results.installed_apps):
            results.error("Django apps to upgraded specified in ENGAGE_MIGRATION_APPS, but south not included in INSTALLED_APPS")
        validate_migration_apps(results.migration_apps, results.installed_apps, results)
    else:
        results.migration_apps = []

    # check the static files directories, if present. Each entry could be a source
    # directory, or a tuple of (target_subdir, source_path)
    if hasattr(settings_module, "STATICFILES_DIRS"):
        staticfiles_dirs = _tuple_setting_to_list(settings_module.STATICFILES_DIRS)
        for dirpath in staticfiles_dirs:
            if isinstance(dirpath, tuple):
                dirpath = dirpath[1]
            if not os.path.isdir(dirpath):
                results.error("Setting STATICFILES_DIRS references '%s', which does not exist" % dirpath)
            elif string.find(os.path.realpath(dirpath),
                             os.path.realpath(app_dir_path)) != 0:
                results.error("Setting STATICFILES_DIRS references '%s', which is not a subdirectory of '%s'" % (dirpath, app_dir_path))
                 
        check_directory_tuple_setting("STATICFILES_DIRS", staticfiles_dirs,
                                      app_dir_path, results)
    # gather the values of static files related settings for use during
    # installation.
    extract_static_files_settings(settings_module, app_dir_path, results)
        
    # check each command in ENGAGE_DJANGO_POSTINSTALL_COMMANDS is actually present in manager
    if hasattr(settings_module, "ENGAGE_DJANGO_POSTINSTALL_COMMANDS"):
        results.post_install_commands = list(settings_module.ENGAGE_DJANGO_POSTINSTALL_COMMANDS)
        validate_post_install_commands(app_name, settings_module, results)
    else:
        results.post_install_commands = []

    # read the additional components file and put the data into the results
    additional_comp_file = os.path.join(app_dir_path, COMPONENTS_FILENAME)
    if os.path.exists(additional_comp_file):
        with open(additional_comp_file, "rb") as cf:
            results.components = read_components_file(cf, additional_comp_file, None)
    else:
        results.components = []

    # validate the user required packages, taking into account the components requested
    # by the user.
    validate_package_list(user_required_packages, results.components, results)
    
    # extract the product name and version, if present
    if hasattr(settings_module, "ENGAGE_PRODUCT_NAME"):
        results.product = settings_module.ENGAGE_PRODUCT_NAME
    if hasattr(settings_module, "ENGAGE_PRODUCT_VERSION"):
        results.product_version = settings_module.ENGAGE_PRODUCT_VERSION

    # if provided, check that the django_config matches the settings values
    if django_config:
        django_config_ok = True
        if installed_apps != django_config.installed_apps:
            results.error("INSTALLED_APPS in configuration file (%s) does not match INSTALLED_APPS in settings file (%s). Your configuration file is likely out of date. Try re-running prepare." %
                          (django_config.installed_apps.__repr__(),
                           installed_apps.__repr__()))
            django_config_ok = False
        if results.fixtures != django_config.fixtures:
            # TODO: this was originally an error, which caused some issues.
            # See ticket #166.
            results.warning("ENGAGE_APP_DB_FIXTURES in configuration file (%s) does not match value in settings file (%s). If this is not what you expect, your configuration file is likely out of date: try re-running prepare." %
                          (django_config.fixtures.__repr__(),
                           results.fixtures.__repr__()))
            django_config_ok = False
        if results.migration_apps != django_config.migration_apps:
            results.error("ENGAGE_MIGRATION_APPS in configuration file (%s) does not match value in settings file (%s). Your configuration file is likely out of date. Try re-running prepare." %
                          (django_config.migration_apps.__repr__(),
                           results.migration_apps.__repr__()))
            django_config_ok = False
        if results.product and results.product != django_config.product:
            results.error("ENGAGE_PRODUCT_NAME in configuration file (%s) does not match value in settings file (%s). Your configuration file is likely out of date. Try re-running prepare." % (django_config.product, results.product))
            django_config_ok = False
        if results.product_version and results.product_version != django_config.product_version:
            results.error("ENGAGE_PRODUCT_VERSION in configuration file (%s) does not match value in settings file (%s). Your configuration file is likely out of date. Try re-running prepare." % (django_config.product_version, results.product_version))
            django_config_ok = False
        if django_config_ok:
            logger.debug("Verified config file is consistent with settings file")

    return results # all done