Пример #1
0
def get_project_config() -> dict:
    """Load the configuration of the current environment (global configuration)"""
    project_config_path = os.path.join(
        Configuration.get_config_path(),
        Configuration.get_config_projet_filename())
    if not io.exists(project_config_path):
        raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT),
                                project_config_path)

    project_config = io.from_yaml(project_config_path)

    return _resolve_variables_deep(project_config)
Пример #2
0
def get_project_config(config_path: str = Configuration.get_config_path()
                       ) -> dict:
    """Load the global configuration of the project"""
    project_config_path = os.path.join(
        config_path, Configuration.get_config_project_filename())
    if not io.exists(project_config_path):
        raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT),
                                project_config_path)

    project_config = yaml_lib.read_yaml(project_config_path)

    return _resolve_variables_deep(project_config)
Пример #3
0
def change_environment(environment: str,
                       config_path=Configuration.get_config_path()):
    """Change the environment (branch) of the configuration"""
    io.execute("git stash", config_path)
    io.execute("git fetch origin", config_path)
    io.execute(f"git checkout {environment}", config_path)
    io.execute(f"git reset --hard origin/{environment}", config_path)
Пример #4
0
def advance_workflow(current_step):
    """Advance the workflow for all applications able to be advanced."""
    Logger.info(
        {"current_step": current_step},
        "[/api/workflow/progress/<current_step>] Workflow advance started",
    )

    try:
        # Creating a copy of the working configuration directory
        config_dir = config_lib.create_temporary_config_copy()
        config_lib.change_environment(
            Configuration.get_config_default_branch(), config_dir)
        project_config = config_lib.get_project_config(config_dir)

        report_status, report = workflow_lib.advance_workflow(
            config_dir, project_config, current_step)

        status, message = _get_status_and_message(report_status)

        # Clean up
        non_blocking_clean(
            config_dir,
            message_prefix="[/api/workflow/progress/<current_step>]")

        # HTTP Response
        Logger.info(
            {
                "current_step": current_step,
                "report": report
            },
            f"[/api/workflow/progress/<current_step>] {message}",
        )
        return (
            {
                "current_step": current_step,
                "report": report,
                "message": message
            },
            status,
        )
    # pylint: disable=broad-except
    except Exception as err:
        Logger.error(
            {
                "current_step": current_step,
                "err": str(err)
            },
            "[/api/workflow/progress/<current_step>] Workflow advance failed",
        )

        # HTTP Response
        return (
            {
                "current_step": current_step,
                "err": str(err),
                "message": "Workflow advance failed",
            },
            HTTPStatus.INTERNAL_SERVER_ERROR,
        )
Пример #5
0
def get_app_config(app_name: str) -> dict:
    """Load the configuration of an app"""
    app_config_path = os.path.join(
        Configuration.get_config_path(),
        Configuration.get_config_app_folder(),
        f"{app_name}.yaml",
    )
    if not io.exists(app_config_path):
        raise AppConfigurationNotFoundError(app_name)

    app_config = io.from_yaml(app_config_path)
    environment_config = get_project_config()

    config = dict_utils.deep_merge(environment_config, app_config)

    # Awaiting for implementation
    # validate configuration using nestor-config-validator

    return _resolve_variables_deep(config)
Пример #6
0
def list_apps_config(config_path: str = Configuration.get_config_path()
                     ) -> dict:
    """Retrieves all of the apps configurations keyed by app names."""
    apps_path = os.path.join(config_path,
                             Configuration.get_config_app_folder())

    if not os.path.isdir(apps_path):
        raise ValueError(apps_path)

    apps_config_hashmap = {}
    for file_path in os.listdir(apps_path):
        basename = os.path.basename(file_path)
        filename = PurePath(basename)
        file_extension = "".join(filename.suffixes)
        app_name = filename.name.replace(file_extension, "")

        # Prevent parsing other files than configuration ones (directories, incorrect extension)
        if file_extension not in [".yml", ".yaml"]:
            continue

        apps_config_hashmap[app_name] = get_app_config(app_name)
    return apps_config_hashmap
Пример #7
0
 def test_get_config_project_filename_configured(self):
     self.assertEqual(Configuration.get_config_project_filename(),
                      "custom-name.yaml")
Пример #8
0
def create_temporary_config_copy() -> str:
    """Copy the configuration into a temporary directory and returns its path"""
    return io.create_temporary_copy(Configuration.get_config_path(), "config")
Пример #9
0
def init_workflow(organization, app):
    """Initialize the workflow of an application."""
    Logger.info(
        {"app": app, "organization": organization},
        "[/api/workflow/init/:org/:app] Workflow initialization started",
    )

    report = None
    try:
        # Retrieve project configuration
        config_dir = config_lib.create_temporary_config_copy()
        config_lib.change_environment(Configuration.get_config_default_branch(), config_dir)
        project_config = config_lib.get_project_config(config_dir)

        git_provider = get_git_provider(project_config)
        report_status, report = workflow_lib.init_workflow(organization, app, git_provider)

        if report_status == workflow_lib.WorkflowInitStatus.FAIL:
            status = HTTPStatus.INTERNAL_SERVER_ERROR
            message = "Workflow initialization failed"
        elif report_status == workflow_lib.WorkflowInitStatus.SUCCESS:
            status = HTTPStatus.OK
            message = "Workflow initialization succeeded"
        else:
            raise ValueError(f"Unexpected status: '{report_status}'")

        # Clean the temporary directory
        try:
            io_lib.remove(config_dir)
        # pylint: disable=broad-except
        except Exception as err:
            Logger.warn(
                {"config_dir": config_dir, "err": err}, "Failed to clean temporary config dir"
            )

        # HTTP Response
        Logger.info(
            {"organization": organization, "app": app, "report": report},
            f"[/api/workflow/init/:org/:app] {message}",
        )
        return (
            {"organization": organization, "app": app, "report": report, "message": message},
            status,
        )
    # pylint: disable=broad-except
    except Exception as err:
        Logger.error(
            {"organization": organization, "app": app, "report": report, "err": str(err)},
            "[/api/workflow/init/:org/:app] Workflow initialization failed",
        )

        # HTTP Response
        return (
            {
                "organization": organization,
                "app": app,
                "err": str(err),
                "message": "Workflow initialization failed",
            },
            HTTPStatus.INTERNAL_SERVER_ERROR,
        )
Пример #10
0
 def test_get_pristine_path_configured(self):
     self.assertEqual(Configuration.get_pristine_path(),
                      "/a-custom-pristine-path")
Пример #11
0
def get_pristine_path(pristine_path_name):
    """Returns the pristine path"""
    return os.path.join(Configuration.get_pristine_path(), pristine_path_name)
Пример #12
0
 def test_get_pristine_path_default(self):
     self.assertEqual(Configuration.get_pristine_path(),
                      "/tmp/nestor/pristine")
Пример #13
0
def test_get_working_path_configured(monkeypatch):
    monkeypatch.setenv("NESTOR_WORK_PATH", "/a-custom-working-path")

    assert Configuration.get_working_path() == "/a-custom-working-path"
Пример #14
0
def test_get_config_path(monkeypatch):
    monkeypatch.setenv("NESTOR_CONFIG_PATH", "/a-custom-config-path")
    assert Configuration.get_config_path() == "/a-custom-config-path"
Пример #15
0
def test_get_pristine_path_configured(monkeypatch):
    monkeypatch.setenv("NESTOR_PRISTINE_PATH", "/a-custom-pristine-path")

    assert Configuration.get_pristine_path() == "/a-custom-pristine-path"
Пример #16
0
 def test_get_config_app_folder_default(self):
     self.assertEqual(Configuration.get_config_app_folder(), "apps")
Пример #17
0
 def test_get_config_app_folder_configured(self):
     self.assertEqual(Configuration.get_config_app_folder(),
                      "/a-custom-apps-folder")
Пример #18
0
 def test_get_working_path_default(self):
     self.assertEqual(Configuration.get_working_path(), "/tmp/nestor/work")
Пример #19
0
 def test_get_working_path_configured(self):
     self.assertEqual(Configuration.get_working_path(),
                      "/a-custom-working-path")
Пример #20
0
def test_get_pristine_path_default():
    assert Configuration.get_pristine_path() == "/tmp/nestor/pristine"
Пример #21
0
 def test_get_config_project_filename_default(self):
     self.assertEqual(Configuration.get_config_project_filename(),
                      "project.yaml")
Пример #22
0
def test_get_working_path_default():
    assert Configuration.get_working_path() == "/tmp/nestor/work"
Пример #23
0
 def test_get_config_default_branch_configured(self):
     self.assertEqual(Configuration.get_config_default_branch(), "master")
Пример #24
0
def _differed_build(app_name: str):
    config_dir = None
    app_dir = None

    try:
        # Retrieve app's configuration
        config_dir = config.create_temporary_config_copy()
        config.change_environment(Configuration.get_config_default_branch(), config_dir)
        app_config = config.get_app_config(app_name, config_dir)
        Logger.debug(
            {"app": app_name, "config_directory": config_dir},
            "[/api/builds/:app] Application's configuration retrieved",
        )

        # Retrieve app's repository
        app_dir = git.create_working_repository(app_name, app_config["git"]["origin"])
        git.branch(app_dir, app_config["workflow"][0])
        Logger.debug(
            {"app": app_name, "working_directory": app_dir},
            "[/api/builds/:app] Application's repository retrieved",
        )

        try:
            # Create a new tag
            version = app.get_version(app_dir)
            git_tag = git.tag(app_dir, version)
            Logger.debug(
                {"app": app_name, "tag": git_tag}, "[/api/builds/:app] New tag created",
            )
        except Exception as err:
            # The tag may already exist
            Logger.warn(
                {"app": app_name, "err": err}, "[/api/builds/:app] Error while tagging the app"
            )

        # Build and publish the new docker image
        image_tag = docker.build(app_name, app_dir, app_config)
        Logger.debug(
            {"app": app_name, "image": image_tag}, "[/api/builds/:app] Docker image created"
        )
        docker.push(app_name, image_tag, app_config)
        Logger.debug(
            {"app": app_name, "image": image_tag},
            "[/api/builds/:app] Docker image published on registry",
        )

        # Send the new tag to git
        git.push(app_dir)
        Logger.debug({"app": app_name}, "[/api/builds/:app] Tag pushed to Git")

    except Exception as err:
        Logger.error(
            {"app": app_name, "err": err},
            "[/api/builds/:app] Error while tagging and building the app",
        )

    # Clean up temporary directories
    try:
        if config_dir is not None:
            io.remove(config_dir)
        if app_dir is not None:
            io.remove(app_dir)
    except Exception as err:
        Logger.error({"app": app_name, "err": err}, "[/api/builds/:app] Error during cleanup")
Пример #25
0
 def test_get_config_default_branch_default(self):
     self.assertEqual(Configuration.get_config_default_branch(), "staging")
Пример #26
0
def get_working_path(working_path_name):
    """Returns the working path"""
    return os.path.join(Configuration.get_working_path(), working_path_name)
Пример #27
0
 def test_get_config_path(self):
     self.assertEqual(Configuration.get_config_path(),
                      "/a-custom-config-path")