Skip to content

Commit

Permalink
Merge pull request #1655 from alan-turing-institute/context
Browse files Browse the repository at this point in the history
Add context command
  • Loading branch information
JimMadge authored Nov 15, 2023
2 parents 653e86d + 84dd4e2 commit 1589db8
Show file tree
Hide file tree
Showing 24 changed files with 892 additions and 345 deletions.
22 changes: 11 additions & 11 deletions .github/workflows/test_code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@ name: Test code
# Run workflow on pushes to matching branches
on: # yamllint disable-line rule:truthy
push:
branches: [develop]
branches: [develop, python-migration]
pull_request:
branches: [develop]
branches: [develop, python-migration]

jobs:
test_powershell:
test_python:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install requirements
shell: pwsh
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
deployment/CheckRequirements.ps1 -InstallMissing -IncludeDev
- name: Test PowerShell
shell: pwsh
run: ./tests/Run_Pester_Tests.ps1
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.11
- name: Install hatch
run: pip install hatch
- name: Test Python
run: hatch run test:test

test_markdown_links:
runs-on: ubuntu-latest
Expand Down
33 changes: 16 additions & 17 deletions data_safe_haven/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ Install the following requirements before starting

- Run the following to initialise the deployment [approx 5 minutes]:

```bash
> dsh init
```console
> dsh context add ...
> dsh context create
```

You will be prompted for various project settings.
If you prefer to enter these at the command line, run `dsh init -h` to see the necessary command line flags.

- Next deploy the Safe Haven Management (SHM) infrastructure [approx 30 minutes]:

```bash
```console
> dsh deploy shm
```

Expand All @@ -29,13 +27,13 @@ Run `dsh deploy shm -h` to see the necessary command line flags and provide them
Note that the phone number must be in full international format.
Note that the country code is the two letter `ISO 3166-1 Alpha-2` code.

```bash
```console
> dsh admin add-users <my CSV users file>
```

- Next deploy the infrastructure for one or more Secure Research Environments (SREs) [approx 30 minutes]:

```bash
```console
> dsh deploy sre <SRE name>
```

Expand All @@ -44,7 +42,7 @@ Run `dsh deploy sre -h` to see the necessary command line flags and provide them

- Next add one or more existing users to your SRE

```bash
```console
> dsh admin register-users -s <SRE name> <username1> <username2>
```

Expand All @@ -54,44 +52,45 @@ where you must specify the usernames for each user you want to add to this SRE

- Run the following to list the currently available users

```bash
```console
> dsh admin list-users
```

## Removing a deployed Data Safe Haven

- Run the following if you want to teardown a deployed SRE:

```bash
```console
> dsh teardown sre <SRE name>
```

- Run the following if you want to teardown the deployed SHM:

```bash
```console
> dsh teardown shm
```

- Run the following if you want to teardown the deployed Data Safe Haven backend:
- Run the following if you want to teardown the deployed Data Safe Haven context:

```bash
> dsh teardown backend
```console
> dsh context teardown
```

## Code structure

- administration
- this is where we keep utility commands for adminstrators of a deployed DSH
- eg. "add a user"; "remove a user from an SRE"
- backend
- context
- in order to use the Pulumi Azure backend we need a KeyVault, Identity and Storage Account
- this code deploys those resources to bootstrap the rest of the Pulumi-based code
- the storage account is also used to store configuration, so that it can be shared by admins
- commands
- the main `dsh` command line entrypoint lives in `cli.py`
- the subsidiary `typer` command line entrypoints (eg. `dsh deploy shm`) live here
- config
- serialises and deserialises a config file from Azure
- `backend_settings` manages basic settings related to the Azure backend: arguably this could/should live in `backend`
- `context_settings` manages basic settings related to the context: arguably this could/should live in `context`
- exceptions
- definitions of a Python exception hierarchy
- external
Expand Down
5 changes: 0 additions & 5 deletions data_safe_haven/backend/__init__.py

This file was deleted.

10 changes: 4 additions & 6 deletions data_safe_haven/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
from data_safe_haven import __version__
from data_safe_haven.commands import (
admin_command_group,
context_command_group,
deploy_command_group,
initialise_command,
teardown_command_group,
)
from data_safe_haven.exceptions import DataSafeHavenError
Expand Down Expand Up @@ -69,6 +69,9 @@ def main() -> None:
name="admin",
help="Perform administrative tasks for a Data Safe Haven deployment.",
)
application.add_typer(
context_command_group, name="context", help="Manage Data Safe Haven contexts."
)
application.add_typer(
deploy_command_group,
name="deploy",
Expand All @@ -80,11 +83,6 @@ def main() -> None:
help="Tear down a Data Safe Haven component.",
)

# Register direct subcommands
application.command(name="init", help="Initialise a Data Safe Haven deployment.")(
initialise_command
)

# Start the application
try:
application()
Expand Down
4 changes: 2 additions & 2 deletions data_safe_haven/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .admin import admin_command_group
from .context import context_command_group
from .deploy import deploy_command_group
from .init import initialise_command
from .teardown import teardown_command_group

__all__ = [
"admin_command_group",
"context_command_group",
"deploy_command_group",
"initialise_command",
"teardown_command_group",
]
174 changes: 174 additions & 0 deletions data_safe_haven/commands/context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""Command group and entrypoints for managing a DSH context"""
from typing import Annotated, Optional

import typer
from rich import print

from data_safe_haven.config import Config, ContextSettings
from data_safe_haven.config.context_settings import default_config_file_path
from data_safe_haven.context import Context
from data_safe_haven.functions import validate_aad_guid

context_command_group = typer.Typer()


@context_command_group.command()
def show() -> None:
"""Show information about the selected context."""
settings = ContextSettings.from_file()

current_context_key = settings.selected
current_context = settings.context

print(f"Current context: [green]{current_context_key}")
print(f"\tName: {current_context.name}")
print(f"\tAdmin Group ID: {current_context.admin_group_id}")
print(f"\tSubscription name: {current_context.subscription_name}")
print(f"\tLocation: {current_context.location}")


@context_command_group.command()
def available() -> None:
"""Show the available contexts."""
settings = ContextSettings.from_file()

current_context_key = settings.selected
available = settings.available

available.remove(current_context_key)
available = [f"[green]{current_context_key}*[/]", *available]

print("\n".join(available))


@context_command_group.command()
def switch(
key: Annotated[str, typer.Argument(help="Key of the context to switch to.")]
) -> None:
"""Switch the selected context."""
settings = ContextSettings.from_file()
settings.selected = key
settings.write()


@context_command_group.command()
def add(
key: Annotated[str, typer.Argument(help="Key of the context to add.")],
admin_group: Annotated[
str,
typer.Option(
help="The ID of an Azure group containing all administrators.",
callback=validate_aad_guid,
),
],
location: Annotated[
str,
typer.Option(
help="The Azure location to deploy resources into.",
),
],
name: Annotated[
str,
typer.Option(
help="The human friendly name to give this Data Safe Haven deployment.",
),
],
subscription: Annotated[
str,
typer.Option(
help="The name of an Azure subscription to deploy resources into.",
),
],
) -> None:
"""Add a new context to the context list."""
if default_config_file_path().exists():
settings = ContextSettings.from_file()
settings.add(
key=key,
admin_group_id=admin_group,
location=location,
name=name,
subscription_name=subscription,
)
else:
# Bootstrap context settings file
settings = ContextSettings(
{
"selected": key,
"contexts": {
key: {
"admin_group_id": admin_group,
"location": location,
"name": name,
"subscription_name": subscription,
}
},
}
)
settings.write()


@context_command_group.command()
def update(
admin_group: Annotated[
Optional[str], # noqa: UP007
typer.Option(
help="The ID of an Azure group containing all administrators.",
callback=validate_aad_guid,
),
] = None,
location: Annotated[
Optional[str], # noqa: UP007
typer.Option(
help="The Azure location to deploy resources into.",
),
] = None,
name: Annotated[
Optional[str], # noqa: UP007
typer.Option(
help="The human friendly name to give this Data Safe Haven deployment.",
),
] = None,
subscription: Annotated[
Optional[str], # noqa: UP007
typer.Option(
help="The name of an Azure subscription to deploy resources into.",
),
] = None,
) -> None:
"""Update the selected context settings."""
settings = ContextSettings.from_file()
settings.update(
admin_group_id=admin_group,
location=location,
name=name,
subscription_name=subscription,
)
settings.write()


@context_command_group.command()
def remove(
key: Annotated[str, typer.Argument(help="Name of the context to remove.")],
) -> None:
"""Remove the selected context."""
settings = ContextSettings.from_file()
settings.remove(key)
settings.write()


@context_command_group.command()
def create() -> None:
"""Create Data Safe Haven context infrastructure."""
config = Config()
context = Context(config)
context.create()
context.config.upload()


@context_command_group.command()
def teardown() -> None:
"""Tear down Data Safe Haven context infrastructure."""
config = Config()
context = Context(config)
context.teardown()
Loading

0 comments on commit 1589db8

Please sign in to comment.