From f368c89c46af4213b8941815ca058f345f6fc331 Mon Sep 17 00:00:00 2001 From: Iain-S <25081046+Iain-S@users.noreply.github.com> Date: Fri, 22 Sep 2023 10:18:58 +0100 Subject: [PATCH] Move instructions to docs/ --- .gitignore | 1 + README.md | 246 +----------------------------------------- docs/conf.py | 1 + docs/content/setup.md | 30 ++++++ docs/content/usage.md | 205 +++++++++++++++++++++++++++++++++++ docs/index.rst | 36 +++++-- poetry.lock | 84 ++++++++++++++- pyproject.toml | 3 +- 8 files changed, 352 insertions(+), 254 deletions(-) create mode 100644 docs/content/setup.md create mode 100644 docs/content/usage.md diff --git a/.gitignore b/.gitignore index 664577f..58e34b5 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,7 @@ instance/ # Sphinx documentation docs/_build/ +docs/_autosummary/ # PyBuilder .pybuilder/ diff --git a/README.md b/README.md index 85cf500..251b8a7 100644 --- a/README.md +++ b/README.md @@ -2,247 +2,5 @@ [![Documentation Status](https://readthedocs.org/projects/rctab-cli/badge/?version=latest)](https://rctab.readthedocs.io/projects/rctab-cli/en/latest/?badge=latest) -A CLI for interacting with the [RCTab API](https://github.com/alan-turing-institute/rctab-api). - -## What it does - -- Add subscriptions to the Research Compute Billing System. -- **Approve credits** for a subscription. - Approved credits are ring fenced for a subscription but can not be spent until they are allocated. -- **Allocate credits** (that have already been approved) to a subscription. - They can now be spent. -- Check all the approvals and allocations made for a subscription. -- Get a summary of all the approvals, allocations and costs for all subscriptions. - -## What it doesn't do (yet) - -- Create subscriptions on Azure. - They must be created through the Azure portal and then added to the billing system. -- Add users to a subscription. - Do this through the Azure portal. - The billing system will then pick them up and you will see the changes on the CLI. - -## Install - -### User install - -```bash -pip install git+https://github.com/alan-turing-institute/rctab-cli -``` - -### Developer Install - -To get started install [Poetry](https://python-poetry.org/docs/). - -Then install dependencies and activate a Poetry shell, which we will assume is active for the rest of the document - -```bash -poetry install -poetry shell -``` - -## Usage - -### Get help - -See documentation and cmds with - -```bash -rctab --help -``` - -Use this to get more information about the commands below - -```bash -rctab --help -``` - -Check you are using the most up to date versions of the CLI and API: - -```bash -rctab --version -``` - -### Configuration - - -When you set up the [RCTab API](https://github.com/alan-turing-institute/rctab-api), you should have [registered an app with the Microsoft identity platform](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). -You will need to set environment variables with the Active Directory Tenant ID and Client ID from that set up process. -You can either do this in the shell, see below, or by adding them to a file named `.auth.env`. - -```shell -export CLIENT_ID="00000000-0000-0000-0000-000000000009" -export TENANT_ID="00000000-0000-0000-0000-00000000000a" -``` - -You will need to set environment variables with the web address and port of your Research Compute API server. -You can either do this in the shell or by adding them to a file named `.env`. - -If you are developing locally, this might look like this - -```bash -export BASE_URL="http://localhost" -export PORT=8000 -``` - -and if you are interacting with a production deployment, it might look like - -```bash -export BASE_URL="https://my-rctab.azurewebsites.net" -export PORT=443 -``` -Make sure that `BASE_URL` has no trailing `/`. -See [config.py](./rctab_cli/config.py) for more - -### Sign in using your AD credentials and request access - -Request access to the API with - -```bash -rctab request-access -``` - -Once you've done this, the `is_admin` flag will need to be set in the RCTab database for you to have CLI access. - -### Managing Subscriptions - -All subcommands for managing subscriptions start with `rctab sub` - -#### Summary of all subscriptions - -To view a summary of all subscriptions run - -```bash -rctab sub summary -``` - -You can filter a single subscription - -```bash -rctab sub summary --subscription-id {SUBSCRIPTION_ID} -``` - -#### See all approvals and allocations - -You can get a detailed information about all the approvals (credits ring fenced for a subscription - these have an expiry date), and allocations (credits ready to spend on a subscription). -The `summary` command provides a summary of these. - -```bash -rctab sub approvals --subscription-id {SUBSCRIPTION_ID} -``` - -```bash -rctab sub allocations --subscription-id {SUBSCRIPTION_ID} -``` - -#### Add a new subscription - -You need to create the subscription on the Azure portal and ensure it is placed in the `EA` management group - otherwise the billing system cannot manage the subscription. Once done, you can add the subscription on to the billing system. - -Run - -```bash -rctab sub add -``` - -If no arguments are provided the CLI will interactively ask you for all the information it requires. -You can also pass these as arguments. -To find out what these are run - -```bash -rctab sub add --help -``` - -You should then check the subscriptions details using the summary command above. - -#### Change persistence - -By default subscriptions are set to expire when they run out of credits or they expire. -However, you can change the 'persistence' of a subscription such that it will always be on. - -```bash -rctab sub set-persistence --subscription-id {SUBSCRIPTION_ID} --persistent -``` - -or to change back - -```bash -rctab sub set-persistence --subscription-id {SUBSCRIPTION_ID} --no-persistent -``` - -#### Approve additional credits - -You can approve more credits on a subscription - -```bash -rctab sub approve --subscription-id {SUBSCRIPTION_ID} --ticket {HELPDESK_TICKET} --amount {GBP} --date-to {EXPIRY_DATE} --allocate -``` - -The {EXPIRY_DATE} is the day the subscription will expire, not the last day it is usable. -For example the date `2020-04-01` means the subscription will last work on the `2022-03-31`. - -The `--allocate` flag will allocate the full approval at the same time. -If you omit this you can allocate a smaller amount of the approval using the allocate command. - -You can set the approval starting date to be in the future with `--date-from {FUTURE-DATE}`. - -#### Remove approved credits - -You can remove credits by making a negative approval. -You must make sure you deallocate credits first and can only remove credits that haven't yet been spent. - -#### Allocate credits - -If you want to approve and allocate credits at the same time use the approve command with the `--allocate` flag. -If you would like to allocate credits that have already been approved use - -```bash -rctab sub allocate --subscription-id {SUBSCRIPTION_ID} --ticket {HELPDESK_TICKET} --amount {GBP} -``` - -#### Deallocate credits - -To remove credits use the above command with a negative allocation. -You may then want to remove the approval for the credits with a negative approval. - -#### Cost recovery process - -It may be desirable to charge a subscription's Azure usage to a particular project or department, which you can do with a two-step process. -First, we specify the subscription ID, the monetary amount & timeframe and the finance code for the project or department who will be billed for the spending: - -```bash -rctab sub finance create --subscription-id '000-000-000-001' --date-from '2022-01' --date-to '2022-04' --amount 7000 --finance-code 'F-ENG-001' -``` - -This will create a Finance entry in the RCTab database, which means that up to £7,000 of subscription 000-000-000-001's spending between Jan and April 2022 (inclusive) will be charged to finance code F-ENG-001. - -Here, `finance` is a separate command for handling finance table operations. You can view the details of these commands by running: - -```bash -rctab sub finance --help -``` - -The second part of the process is to calculate recoverable costs for all subscriptions for previous months (in order) - -```bash -$ rctab sub cost-recovery --month 2022-01 -... -$ rctab sub cost-recovery --month 2022-02 -... -``` - -These must be run in order and should be run exactly once for each previous month (you can start on any month before the earliest Finance entry start date). - -If you need to modify a Finance entry, you can list the entries for a subscription with - -```bash -$ rctab sub finance list --subscription-id 000-000-000-001 -[{...'id': 59}] -``` - -where we see that our subscription has one Finance entry with an ID of 59. -We can then use this Finance ID to update the Finance entry, as long as it would not conflict with cost already recovered: - -```bash -rctab sub finance update --amount 6000 --finance-id 59 --subscription-id '000-000-000-001' -``` +This is the CLI for RCTab. +You can find the full RCTab docs [here](https://rctab.readthedocs.io/), the online CLI documentation [here](https://rctab-cli.readthedocs.io/) and the documentation source code in [docs/](docs/). diff --git a/docs/conf.py b/docs/conf.py index 1299272..586ced8 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,7 @@ "sphinx.ext.autodoc", "sphinx.ext.autosummary", "sphinx.ext.intersphinx", + "myst_parser", # "subprojecttoctree", ] diff --git a/docs/content/setup.md b/docs/content/setup.md new file mode 100644 index 0000000..36d8385 --- /dev/null +++ b/docs/content/setup.md @@ -0,0 +1,30 @@ +# Installation + +## User Install + +```bash +pip install git+https://github.com/alan-turing-institute/rctab-cli +``` + +## Developer Install + +To get started install [Poetry](https://python-poetry.org/docs/). + +Then from the root of the repository, install dependencies and activate a Poetry shell, which we will assume is active for the rest of the document, with + +```bash +poetry install +poetry shell +``` + +You should also install [pre-commit](https://pre-commit.com) and install the pre-commit hooks with + +```bash +pre-commit install --install-hooks +``` + +and check that all hooks pass by running + +```bash +pre-commit run --all-files +``` diff --git a/docs/content/usage.md b/docs/content/usage.md new file mode 100644 index 0000000..e17671b --- /dev/null +++ b/docs/content/usage.md @@ -0,0 +1,205 @@ +# Usage + +## Get help + +See documentation and available commands with + +```bash +rctab --help +``` + +Use this to get more information about any one command, use + +```bash +rctab --help +``` + +Check you are using the most up to date versions of the CLI and API: + +```bash +rctab --version +``` + +## Configuration + +When you set up the [RCTab API](https://github.com/alan-turing-institute/rctab-api), you should have [registered an app with the Microsoft identity platform](https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app). +You will need to set environment variables with the Active Directory Tenant ID and Client ID from that set up process. +You can either do this in the shell, see below, or by adding them to a file named `.auth.env`. + +```shell +export CLIENT_ID="00000000-0000-0000-0000-000000000009" +export TENANT_ID="00000000-0000-0000-0000-00000000000a" +``` + +You will also need to set environment variables with the web address and port of your RCTab API server. +You can either do this in the shell or by adding them to a file named `.env`. + +If you are developing locally, this might look like this + +```bash +export BASE_URL="http://localhost" +export PORT=8000 +``` + +and if you are interacting with a production deployment, it might look like + +```bash +export BASE_URL="https://my-rctab.azurewebsites.net" +export PORT=443 +``` + +Make sure that `BASE_URL` has no trailing `/`. +See the config.py module for more. + +## Sign in using your AD credentials and request access + +Request access to the API with + +```bash +rctab request-access +``` + +Once you've done this, the `is_admin` flag will need to be set in the RCTab database for you to have CLI access. + +## Managing Subscriptions + +All subcommands for managing subscriptions start with `rctab sub` + +### Summary of all subscriptions + +To view a summary of all subscriptions run + +```bash +rctab sub summary +``` + +You can filter a single subscription + +```bash +rctab sub summary --subscription-id {SUBSCRIPTION_ID} +``` + +### See all approvals and allocations + +You can get a detailed information about all the approvals (credits ring fenced for a subscription - these have an expiry date), and allocations (credits ready to spend on a subscription). +The `summary` command provides a summary of these. + +```bash +rctab sub approvals --subscription-id {SUBSCRIPTION_ID} +``` + +```bash +rctab sub allocations --subscription-id {SUBSCRIPTION_ID} +``` + +### Add a new subscription + +You need to create the subscription on the Azure portal and ensure it is placed in the `EA` management group - otherwise the billing system cannot manage the subscription. Once done, you can add the subscription on to the billing system. + +Run + +```bash +rctab sub add +``` + +If no arguments are provided the CLI will interactively ask you for all the information it requires. +You can also pass these as arguments. +To find out what these are run + +```bash +rctab sub add --help +``` + +You should then check the subscriptions details using the summary command above. + +### Change persistence + +By default subscriptions are set to expire when they run out of credits or they expire. +However, you can change the 'persistence' of a subscription such that it will always be on. + +```bash +rctab sub set-persistence --subscription-id {SUBSCRIPTION_ID} --persistent +``` + +or to change back + +```bash +rctab sub set-persistence --subscription-id {SUBSCRIPTION_ID} --no-persistent +``` + +### Approve additional credits + +You can approve more credits on a subscription + +```bash +rctab sub approve --subscription-id {SUBSCRIPTION_ID} --ticket {HELPDESK_TICKET} --amount {GBP} --date-to {EXPIRY_DATE} --allocate +``` + +The {EXPIRY_DATE} is the day the subscription will expire, not the last day it is usable. +For example the date `2020-04-01` means the subscription will last work on the `2022-03-31`. + +The `--allocate` flag will allocate the full approval at the same time. +If you omit this you can allocate a smaller amount of the approval using the allocate command. + +You can set the approval starting date to be in the future with `--date-from {FUTURE-DATE}`. + +### Remove approved credits + +You can remove credits by making a negative approval. +You must make sure you deallocate credits first and can only remove credits that haven't yet been spent. + +### Allocate credits + +If you want to approve and allocate credits at the same time use the approve command with the `--allocate` flag. +If you would like to allocate credits that have already been approved use + +```bash +rctab sub allocate --subscription-id {SUBSCRIPTION_ID} --ticket {HELPDESK_TICKET} --amount {GBP} +``` + +### Deallocate credits + +To remove credits use the above command with a negative allocation. +You may then want to remove the approval for the credits with a negative approval. + +### Cost recovery process + +It may be desirable to charge a subscription's Azure usage to a particular project or department, which you can do with a two-step process. +First, we specify the subscription ID, the monetary amount & timeframe and the finance code for the project or department who will be billed for the spending: + +```bash +rctab sub finance create --subscription-id '000-000-000-001' --date-from '2022-01' --date-to '2022-04' --amount 7000 --finance-code 'F-ENG-001' +``` + +This will create a Finance entry in the RCTab database, which means that up to £7,000 of subscription 000-000-000-001's spending between Jan and April 2022 (inclusive) will be charged to finance code F-ENG-001. + +Here, `finance` is a separate command for handling finance table operations. You can view the details of these commands by running: + +```bash +rctab sub finance --help +``` + +The second part of the process is to calculate recoverable costs for all subscriptions for previous months (in order) + +```bash +$ rctab sub cost-recovery --month 2022-01 +... +$ rctab sub cost-recovery --month 2022-02 +... +``` + +These must be run in order and should be run exactly once for each previous month (you can start on any month before the earliest Finance entry start date). + +If you need to modify a Finance entry, you can list the entries for a subscription with + +```bash +$ rctab sub finance list --subscription-id 000-000-000-001 +[{...'id': 59}] +``` + +where we see that our subscription has one Finance entry with an ID of 59. +We can then use this Finance ID to update the Finance entry, as long as it would not conflict with cost already recovered: + +```bash +rctab sub finance update --amount 6000 --finance-id 59 --subscription-id '000-000-000-001' +``` diff --git a/docs/index.rst b/docs/index.rst index f7ea61f..e67f615 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,22 +1,44 @@ -.. rctab-cli documentation master file, created by - sphinx-quickstart on Thu Sep 14 19:26:19 2023. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +Welcome to the RCTab CLI documentation! +======================================= -Welcome to rctab-cli's documentation! -===================================== +This CLI can be used to request administrator access and can be used by admins to + +* Add subscriptions to the Research Compute Billing System. +* Approve credits for a subscription. + Approved credits are ring fenced for a subscription but can not be spent until they are allocated. +* Allocate credits (that have already been approved) to a subscription. + They can now be spent. +* Check all the approvals and allocations made for a subscription. +* Get a summary of all the approvals, allocations and costs for all subscriptions. + +The CLI can't be used to + +* Create subscriptions on Azure. + They must be created through the Azure portal and then added to the RCTab with the ``rctab sub add`` command. +* Add users to a subscription. + Do this by other means such as through the Azure portal or with the Azure CLI. .. .. subprojecttoctree:: :maxdepth: 2 :caption: Contents: +.. toctree:: + :maxdepth: 2 + :caption: External Links + :glob: + :hidden: + + RCTab docs home + .. toctree:: :maxdepth: 2 :caption: Contents :hidden: + :glob: - sometext + Home + content/* .. autosummary:: :toctree: _autosummary diff --git a/poetry.lock b/poetry.lock index d02403d..e01783a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -807,6 +807,30 @@ files = [ {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, ] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = true +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + [[package]] name = "markupsafe" version = "2.1.3" @@ -877,6 +901,36 @@ files = [ {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] +[[package]] +name = "mdit-py-plugins" +version = "0.4.0" +description = "Collection of plugins for markdown-it-py" +optional = true +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, + {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = true +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + [[package]] name = "msal" version = "1.23.0" @@ -1028,6 +1082,32 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "myst-parser" +version = "2.0.0" +description = "An extended [CommonMark](https://spec.commonmark.org/) compliant parser," +optional = true +python-versions = ">=3.8" +files = [ + {file = "myst_parser-2.0.0-py3-none-any.whl", hash = "sha256:7c36344ae39c8e740dad7fdabf5aa6fc4897a813083c6cc9990044eb93656b14"}, + {file = "myst_parser-2.0.0.tar.gz", hash = "sha256:ea929a67a6a0b1683cdbe19b8d2e724cd7643f8aa3e7bb18dd65beac3483bead"}, +] + +[package.dependencies] +docutils = ">=0.16,<0.21" +jinja2 = "*" +markdown-it-py = ">=3.0,<4.0" +mdit-py-plugins = ">=0.4,<1.0" +pyyaml = "*" +sphinx = ">=6,<8" + +[package.extras] +code-style = ["pre-commit (>=3.0,<4.0)"] +linkify = ["linkify-it-py (>=2.0,<3.0)"] +rtd = ["ipython", "pydata-sphinx-theme (==v0.13.0rc4)", "sphinx-autodoc2 (>=0.4.2,<0.5.0)", "sphinx-book-theme (==1.0.0rc2)", "sphinx-copybutton", "sphinx-design2", "sphinx-pyscript", "sphinx-tippy (>=0.3.1)", "sphinx-togglebutton", "sphinxext-opengraph (>=0.8.2,<0.9.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] +testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=7,<8)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx-pytest"] +testing-docutils = ["pygments", "pytest (>=7,<8)", "pytest-param-files (>=0.3.4,<0.4.0)"] + [[package]] name = "nodeenv" version = "1.8.0" @@ -2042,9 +2122,9 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [extras] -docs = ["sphinx-rtd-theme", "sphinx-subprojecttoctree", "sphinxcontrib-napoleon"] +docs = ["myst-parser", "sphinx-rtd-theme", "sphinx-subprojecttoctree", "sphinxcontrib-napoleon"] [metadata] lock-version = "2.0" python-versions = "^3.8.0" -content-hash = "a262cc16c313956c59fc301377be02f8d1c2999fdf19e0250e1574999b8fe865" +content-hash = "f7531457255395f7ed025218fed2889c9240b871c45a6e10e60d396aef03703a" diff --git a/pyproject.toml b/pyproject.toml index c3a1840..8713aa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,7 @@ importlib = "^1.0.4" sphinxcontrib-napoleon = {version = "^0.7", optional = true} sphinx-rtd-theme = {version = "^1.3.0", optional = true} sphinx-subprojecttoctree = {version = "^0.5.1", optional = true} +myst-parser = {version = "^2.0.0", optional = true} [tool.poetry.dev-dependencies] pytest = "^7.1.3" @@ -33,7 +34,7 @@ pydocstyle = "^6.3.0" pylint-absolute-imports = "^1.0.1" [tool.poetry.extras] -docs = ["sphinx-rtd-theme", "sphinxcontrib-napoleon", "sphinx-subprojecttoctree"] +docs = ["myst-parser", "sphinx-rtd-theme", "sphinxcontrib-napoleon", "sphinx-subprojecttoctree"] [tool.isort] profile = "black"