
# fbnconfig

[![pypi](https://img.shields.io/pypi/v/fbnconfig)](https://pypi.org/project/fbnconfig/)
[![python](https://img.shields.io/pypi/pyversions/fbnconfig.svg)](https://pypi.python.org/pypi/fbnconfig)

## Overview

`fbnconfig` is a configuration management tool designed to help deploy and manage configurations for various resources within the LUSID ecosystem. It ensures that an environment aligns with the desired configuration by managing resources, tracking state changes, and handling dependencies effectively.

## Getting started

### Prerequisites

Ensure you have the following installed:

* Python 3.11+
* [pipx](https://pipx.pypa.io/stable/installation/)
* Docker (for running resources that depend on images)
  * Note that examples using harbor images need the host to be logged in to harbor.Run `docker login harbor.finbourne.com`
and use the credentials from your user profile(top right corner) from here https://harbor.finbourne.com/harbor/projects
* [uv](https://docs.astral.sh/uv/getting-started/installation/)
* [Mise](https://mise.jdx.dev/getting-started.html) (optional)

### Clone the Repository

```Bash
git clone git@gitlab.com:finbourne/clientengineering/fbnconfig.git
```

### Setup

#### For macOS/Linux

1. Create a Virtual Environment and Install Dependencies

   ```Bash
   uv sync
   source .venv/bin/activate
   ```

#### For Windows

1. Create a Virtual Environment and Install Dependencies

   ```powershell
    uv sync
   .\.venv\Scripts\Activate
   ```
## One-Time Setup

Before running a deployment, a one-time per-domain setup is required to create a CustomEntityDefinition for deployment logs.

### Using the CLI

Ensure the appropriate environment variables are set, then run:

```bash
fbnconfig setup
```

### Using the Library

```python
import fbnconfig
import os

lusid_env = os.environ["LUSID_ENV"]
token = os.environ["FBN_ACCESS_TOKEN"]
client = fbnconfig.create_client(lusid_env, token)
fbnconfig.setup(client)
```

## Running an Example

This example assumes:

* You want to test in `fbn-qa.lusid.com`.
* You have the [1Password CLI installed](https://developer.1password.com/docs/cli/)
* You have a [PAT set up](https://support.lusid.com/knowledgebase/article/KA-01774) and stored as a password in your personal 1Password vault with an item name 'fbn-qa-pat'.

1. Export your access token:

   ```Bash
   export FBN_ACCESS_TOKEN="$(op read op://Private/fbn-qa-pat/password)"
   ```

2. Run the example:

   ```Bash
   python examples/drive.py -v examples/var_file.json https://fbn-qa.lusid.com
   ```

This example deploys some folders and a text file into Drive, creating a base directory as per the configuration provided in the vars file [examples/var_file.json](/examples/var_file.json) (defaults to `fbnconfig_test`), which is passed in using the `-v` flag. The other folders and the file to be created are defined explicitly in [examples/folder.py](/examples/drive.py). Any folders or files to be written may already exist, in which case the tool will say that they are not changing.

If successful, you should see these folders in Drive. Modify the names or add another folder and run again to see the changes.

## Licenses needed

* scheduler-modify-images-all-status-access

## Format and Lint

Use `ruff` to check whether code follows conventions and apply fix:

```Bash
ruff check --fix
```

## Documentation

A resource represents a desired configuration. The tool's job is to converge the environment to that configuration. The user specifies the desired state, and the tool determines how to adjust the remote state accordingly.

### Log Tracking

Log tracking is necessary when:

1. **Deleting resources no longer in the desired state**: The log helps determine what has been removed.

2. **Handling autogenerated IDs**: If a resource has an autogenerated ID and the user wants to change its identifier, the log keeps track of the old ID to manage the transition.

3. **Managing resource dependencies**: If a resource has a dependency to another resource and the user changes this relationship, the log records the old value to manage the connection.

### Creating Resources

The `create` method is responsible for creating new entities. It assumes the entity does not exist and handles any conflict errors manually. Dependent resources should be created beforehand.

### Updating Resources

The `update` method transitions from the current state to the desired state. It compares the remote resource with the desired state and only makes updates if there are changes. Default values set by the server should not be overwritten unless specified by the user. For example:

* No change scenario:
  * Remote state: `effectiveFrom: 2023, effectiveTo: 9999`
  * Desired state: `effectiveFrom: 2023`
  * Result: No update needed.
* Change scenario:
  * Desired state: `effectiveFrom: 2023, effectiveTo: 3000`
  * Result: Update applied.

## Deleting Resources

The `delete` method removes the resource completely. Dependent resources should be cleaned up before calling delete. For example, if a deployment includes `a_job` and `a_schedule`:

```python
a_job = scheduler.JobResource(...)
a_schedule = scheduler.schedule(..., job=a_job)
return Deployment('a_deployment', [a_job, a_schedule])
```

And then changes to:

```python
return Deployment('a_deployment', [])
```

Both `a_job` and `a_schedule` should be deleted, with `a_schedule` being deleted first due to its dependency on `a_job`.

## Handling Dependencies (deps)

The `deps` method returns any resources that a resource depends on. For example:

```python
a_folder = drive.FolderResource(...)
a_file = drive.FileResource(..., folder=a_folder)
```

`a_file` depends on `a_folder`. The `deps` method calculates the build order to ensure `a_folder` exists before creating `a_file`.

## Managing Defaults - TBC

Defaults can be tricky to handle. If the API defaults a value to "now" or any other dynamic value, the update method must be careful not to overwrite this unless explicitly specified by the user.

## Additional Notes

* Assign policy to user: <https://support.lusid.com/knowledgebase/article/KA-01699/>
* Create user in Identity and Access: <https://support.lusid.com/knowledgebase/article/KA-01653/>
* IAM Introduction: <https://support.lusid.com/knowledgebase/article/KA-01647/>
* Scheduler permissions:  <https://support.lusid.com/knowledgebase/article/KA-01673/en-us>
