Skip to content

Commit

Permalink
Merge pull request #1073 from gchq/chore/documentation-admin
Browse files Browse the repository at this point in the history
Update administration documentation
  • Loading branch information
a3957273 authored Feb 16, 2024
2 parents 935c91f + a08ed63 commit 26c65b7
Show file tree
Hide file tree
Showing 8 changed files with 438 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import DocsWrapper from 'src/docs/DocsWrapper'

# App Configuration

## Configuration Files

> ⚠️ Note: If you use Helm this information does not apply to you. We use Helm to automatically configure the
> application for you. Within helm you can manually alter this configuration in
> `infrastructure/helm/bailo/templates/bailo/bailo.configmap.yaml`
Bailo uses [`node-config`](https://github.com/node-config/node-config#readme) for application configuration.
`node-config` organizes hierarchical configurations, allowing the user to set a series of overides over a base
configuration.

The default set of configuration can be found in `config/default.js`, with overrides for other environments included in
the same folder. For production environments, configuration should be placed in either `production.cjs` or `local.js` to
override the default configuration.

The full order of configuration inheritance can be found
[on the node-config wiki](https://github.com/node-config/node-config/wiki/Configuration-Files).

Given the following set of files:

```javascript
// default.js
{ a: 5, b: "ten", c: { d: 20, e: 25 } }

// production.cjs
{ b: 10, c: { d: "d" } }

// local.js
{ c: { d: 999 } }
```

The result is:

```javascript
{
a: 5, // no overrides
b: 10, // overridden in production.cjs
c: {
d: 999, // overriden in production.cjs, then again in local.js
e: 25 // not overwritten, objects are merged together.
}
}
```

When deploying using `helm`, configuration is primarily handled through `values.yaml` controlling
`helm/bailo/templates/bailo/bailo.configmap.yaml`. Configuration is loaded when the application starts. The application
must be restarted when configuration changes.

export default ({ children }) => <DocsWrapper>{children}</DocsWrapper>
51 changes: 51 additions & 0 deletions frontend/pages/docs/administration/helm/basic-usage.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import DocsWrapper from 'src/docs/DocsWrapper'

# Helm Deployments

If you are deploying to a Kubernetes or OpenShift cluster, Helm is the only supported method of deployment. It is a
package manager for Kubernetes and allows us to simplify installing and upgrading the project. It enables you to use the
same base templates for deploying Bailo, configuring overrides to values as needed for your specific use case.

For more details, see the [Helm project page](https://helm.sh/).

## Requirements

- [HELM CLI](https://github.com/helm/helm/releases)
- [Kubectl](https://kubernetes.io/docs/tasks/tools/)

If you are deploying to OpenShift, you will also need OC:

- [OpenShift CLI](https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz)

## Deployment

### Setup

All commands assume they are run in the `infrastructure/helm/bailo` directory. You should have already authenticated
`kubectl` to their cluster and changed to the correct context:

1. `kubectl config set-context --current --namespace=bailo`

You can test out your connection by running:

1. `kubectl cluster-info`

When Deploying to OpenShift login to `oc` instead:

1. `oc login <openshift url>`

### Installation

1. `helm dependency update`
2. `helm install bailo .`
3. `helm list # check the installation exists`

### Upgrade

1. `helm upgrade bailo .`

### Remove

1. `helm uninstall bailo`

export default ({ children }) => <DocsWrapper>{children}</DocsWrapper>
41 changes: 41 additions & 0 deletions frontend/pages/docs/administration/helm/configuration.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import DocsWrapper from 'src/docs/DocsWrapper'

# Helm Configuration

The default Helm configuration is stored within `values.yaml`. You should not alter this configuration directly, instead
overriding individual values via the command line `--set` flag, or by providing a custom `--values` file.

To override a single value, add `--set <option>=<value>` to either the `helm install` and `helm upgrade` commands you
run. To overide multiple values, create a `local.yaml` (or a deployment specific name like `ops.yaml`) file and add
`--values local.yaml` to your `helm install` and `helm upgrade` commands. For example:

```yaml
# reference.yaml

image:
frontendRepository: 'internal.docker.registry'
frontendTag: 'v2.0.3-rc.0'
```
Would be installed and upgraded using:
```bash
$ helm install --values reference.yaml bailo .
$ helm upgrade --values reference.yaml bailo .
```

We do not host built images of Bailo, thus at the very minimum the custom configuration should include the following:

```yaml
# local.yaml

image:
frontendRepository: '<docker registry>'
frontendTag: 'v2.1.2'
backendRepository: '<docker registry>'
backendTag: 'v2.1.2'
```
To create these images, follow the instructions in [Building Bailo Images](../building-the-bailo-image).
export default ({ children }) => <DocsWrapper>{children}</DocsWrapper>
42 changes: 42 additions & 0 deletions frontend/pages/docs/administration/helm/isolated-environments.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import DocsWrapper from 'src/docs/DocsWrapper'

# Isolated Environments

Bailo is built to be deployed on isolated environments, where access to the internet is strictly regulated. To install
Bailo on a segregated environment you will need the following dependencies.

## Helm Charts

We rely on the following Bitnami charts:

- MinIO https://charts.bitnami.com/bitnami
- MongoDB https://charts.bitnami.com/bitnami

## Docker Images

We rely on the following images:

- mongo:6.0.4
- minio/minio:RELEASE.2023-01-31T02-24-19Z
- marlonb/mailcrab:v0.10.0
- nginx:1.21.6-alpine
- registry:2.8.1
- node:18-alpine

These will occassionally be updated. To retrieve the latest versions used, check `./docker-compose.yml` and
`./backend/Dockerfile`. These versions can be configured using the `tag` attribute for each image in `values.yaml` to
override the defaults. In general, keeping to the same major version will maintain compatability with Bailo.

## NPM

We rely on many NPM packages. The full list is available in `package-lock.json`, `frontend/package-lock.json` and
`backend/package-lock.json`. Most are standard packages with the exception of:

- `sharp`, which is an optimised image transformer and requires some compilation tools.
- `cypress`, which is a user interface testing tool and requires a Chromium download.

`sharp` includes instructions on installing / building without internet [here](https://sharp.pixelplumbing.com/install).
Instructions on installing `cypress` without internet are available
[here](https://docs.cypress.io/guides/references/advanced-installation).

export default ({ children }) => <DocsWrapper>{children}</DocsWrapper>
199 changes: 199 additions & 0 deletions frontend/pages/docs/administration/schemas/create-a-schema.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import DocsWrapper from 'src/docs/DocsWrapper'

# Creating and Uploading schemas

Bailo makes use of the [RJSF](https://react-jsonschema-form.readthedocs.io/en/latest/) (react-jsonschema-form) library
in order to dynamically create its upload & access request forms. These forms are constructed using existing widgets, or
custom widgets that have been created specifically for Bailo.

## Example / minimal schemas

Bailo includes both an example schema for uploads and for deployments. You can find them in
`backend/src/scripts/example_schemas`. It is important to note that these schemas contain all of mandatory fields that
the application needs in order to run. These fields are hard-coded in various places in the source code.

## Create a schema

### Simple questions

A typical object inside the schema will look like this:

```json
"firstName": {
"type": "string",
"title": "First name",
"default": "Chuck",
"description": "This is for your first name"
}
```

The type property can be altered depending on what value you want the question to return. The title property will be
displayed as the question itself, and the description will appear under the question to include any additional
information that might help the user. Please note that if you do not include a title property, the library will use the
name of the object (in this case firstName) instead.

### Dates

Dates can be added like this:

```json
"date": {
"type": "string",
"title": "Date of birth",
"format": "date"
}
```

### Sections

When using Bailo you will see that the upload form is made up of a number of pages. Each page is a separate object
inside the first "properties" property of the schema. For example:

```json
"properties": {
"firstPage": {
"type": "object",
"title": "Page 1",
"properties": {
...
}
},
"secondPage": {
"type": "object",
"title": "Page 2",
"properties": {
...
}
}
}
```

Creating sub-sections works identically to how we defined our pages above. If we take the first page of our example
above, and then amend it so it looks like this:

```json
"properties": {
"firstPage": {
"type": "object",
"title": "Page 1",
"properties": {
"sectionOne": {
"type": "object",
"title": "Section 1"
"properties": {
"questionOne": {
"type": "number",
"title": "Enter a number",
}
}
},
"sectionTwo": {
"type": "object",
"title": "Section 2"
"properties": {
"questionTwo": {
"type": "string",
"title": "Enter a string",
}
}
}
},
...
}
```

#### Hiding sections from the model card

Sections will display on the model card page by default, but in the case whereby a section needs to be hidden from the
model card, then add the following property:

```json
"myPage": {
"title": "Page 1",
"type": "object",
"properties": {
...
},
"displayModelCard": false,
}
```

Note: This will only hide it from the model page, the data will still persist in the version metadata.

### Dependencies

A dependency is useful when the answer to one question might warrant some additional information; for example, a boolean
question might not need a detailed response if the answer is 'no', but if the user answer is 'yes' you might want to ask
them for some additional details.

To avoid validation errors, Bailo schema dependencies need to be handled slightly differently to the ones provided in
the RJSF documentation. Here is an example of how we handle dependencies for Bailo schemas:

```json
"myPage": {
"title": "Page 1",
"type": "object",
"properties": {
"questionOne": {
"type": "boolean",
"title": "True or false?",
},
"questionTwo": {
"title": "More information please!",
"type": "string",
}
},
"dependencies": {
"questionOne": {
"oneOf": [
{
"properties": {
"questionOne": {
"enum": [false],
"readOnly": false
},
"questionTwo": {
"readOnly": true
}
},
"required": ["questionOne"],
"additionalProperties": false
},
{
"properties": {
"questionOne": {
"enum": [true],
"readOnly": false
},
"questionTwo": {
"readOnly": false
}
},
"required": ["questionOne", "questionTwo"],
"additionalProperties": false
}
]
}
},
"required": ["questionOne"]
}
```

Inside `dependencies` we have defined a case of only having one of two different situations. Firstly, if `questionOne`
is set to `false`, then `questionTwo` will be set to read only, whereas if we set `questionOne` to `true` then
`questionTwo` will not be set as read only. This method might seem slightly more convoluted than the documentation
online, but it allows for answers to be changed without making the schema invalid. The current design of RJSF's
dependencies works as so:

- User selects `true` for `questionOne`
- User enters data into `questionTwo`
- User changes their mind and selects `false` for `questionOne`
- User data for `questionTwo` remains in the form data, despite not being visible on the form itself

This behaviour is so that any user data is retained in case the user wishes to select `true` for `questionOne` again.
From a user perspective this nice as it means there is less chance of data being lost when changing answers, but it does
have a knock-on affect whereby in certain situations it will make the schema fail validation. Our approach is set the
additional questions to read only when they are not in use. The downside to this approach is that we potentially include
unwanted additional data, but this can be removed by the user if this happens.

export default ({ children }) => <DocsWrapper>{children}</DocsWrapper>
Loading

0 comments on commit 26c65b7

Please sign in to comment.