From eb8d7e9a9f0a9d1452b6bab98f310b40486bb0a7 Mon Sep 17 00:00:00 2001 From: Lena Garber Date: Wed, 28 Aug 2024 14:53:39 -0400 Subject: [PATCH 01/39] Add generated documentation site (squashed) --- .github/workflows/publish-wiki.yml | 18 -- .gitignore | 1 + Makefile | 16 ++ docs/Makefile | 20 ++ docs/commands/index.rst | 8 + docs/conf.py | 40 +++ docs/development/guides/01-overview.rst | 150 ++++++++++ docs/development/guides/02-setup.rst | 78 ++++++ .../guides/03-project-skeleton.rst | 164 +++++++++++ docs/development/guides/04-testing.rst | 34 +++ docs/development/index.rst | 15 + docs/general/guides/01-installation.rst | 93 +++++++ .../general/guides/02-configuration.rst | 78 +++--- docs/general/guides/03-usage.rst | 176 ++++++++++++ .../general/guides/04-output.rst | 60 ++-- .../general/guides/05-plugins.rst | 25 +- docs/general/index.rst | 9 + docs/index.rst | 21 ++ docs/plugins/development.rst | 147 ++++++++++ docs/plugins/index.rst | 13 + docs/static/demo.gif | Bin 0 -> 180306 bytes docs/static/favicon.ico | Bin 0 -> 16958 bytes docs/static/logo.svg | 36 +++ docs/static/overlay.css | 37 +++ linodecli/__init__.py | 14 +- linodecli/baked/operation.py | 45 ++- linodecli/baked/parsing.py | 7 +- linodecli/baked/response.py | 8 +- linodecli/documentation/__init__.py | 0 linodecli/documentation/generator.py | 59 ++++ linodecli/documentation/template_data.py | 256 ++++++++++++++++++ .../documentation/templates/group.rst.j2 | 139 ++++++++++ linodecli/documentation/util.py | 110 ++++++++ linodecli/helpers.py | 35 ++- linodecli/plugins/README.md | 139 ---------- pyproject.toml | 10 +- wiki/Home.md | 4 - wiki/Installation.md | 69 ----- wiki/Usage.md | 180 ------------ wiki/_Sidebar.md | 10 - wiki/development/Development - Index.md | 12 - wiki/development/Development - Overview.md | 104 ------- wiki/development/Development - Setup.md | 86 ------ wiki/development/Development - Skeleton.md | 32 --- wiki/development/Development - Testing.md | 31 --- 45 files changed, 1810 insertions(+), 779 deletions(-) delete mode 100644 .github/workflows/publish-wiki.yml create mode 100644 docs/Makefile create mode 100644 docs/commands/index.rst create mode 100644 docs/conf.py create mode 100644 docs/development/guides/01-overview.rst create mode 100644 docs/development/guides/02-setup.rst create mode 100644 docs/development/guides/03-project-skeleton.rst create mode 100644 docs/development/guides/04-testing.rst create mode 100644 docs/development/index.rst create mode 100644 docs/general/guides/01-installation.rst rename wiki/Configuration.md => docs/general/guides/02-configuration.rst (58%) create mode 100644 docs/general/guides/03-usage.rst rename wiki/Output.md => docs/general/guides/04-output.rst (53%) rename wiki/Plugins.md => docs/general/guides/05-plugins.rst (63%) create mode 100644 docs/general/index.rst create mode 100644 docs/index.rst create mode 100644 docs/plugins/development.rst create mode 100644 docs/plugins/index.rst create mode 100644 docs/static/demo.gif create mode 100644 docs/static/favicon.ico create mode 100644 docs/static/logo.svg create mode 100644 docs/static/overlay.css create mode 100644 linodecli/documentation/__init__.py create mode 100644 linodecli/documentation/generator.py create mode 100644 linodecli/documentation/template_data.py create mode 100644 linodecli/documentation/templates/group.rst.j2 create mode 100644 linodecli/documentation/util.py delete mode 100644 linodecli/plugins/README.md delete mode 100644 wiki/Home.md delete mode 100644 wiki/Installation.md delete mode 100644 wiki/Usage.md delete mode 100644 wiki/_Sidebar.md delete mode 100644 wiki/development/Development - Index.md delete mode 100644 wiki/development/Development - Overview.md delete mode 100644 wiki/development/Development - Setup.md delete mode 100644 wiki/development/Development - Skeleton.md delete mode 100644 wiki/development/Development - Testing.md diff --git a/.github/workflows/publish-wiki.yml b/.github/workflows/publish-wiki.yml deleted file mode 100644 index b063d0217..000000000 --- a/.github/workflows/publish-wiki.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: Publish wiki -on: - push: - branches: [main] - paths: - - wiki/** - - .github/workflows/publish-wiki.yml -concurrency: - group: publish-wiki - cancel-in-progress: true -permissions: - contents: write -jobs: - publish-wiki: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: Andrew-Chen-Wang/github-wiki-action@50650fccf3a10f741995523cf9708c53cec8912a # pin@v4.4.0 diff --git a/.gitignore b/.gitignore index 77601cba7..09375efef 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ test/.env MANIFEST venv openapi*.yaml +_generated diff --git a/Makefile b/Makefile index 69720a1ab..662711835 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ VERSION_FILE := ./linodecli/version.py VERSION_MODULE_DOCSTRING ?= \"\"\"\nThe version of the Linode CLI.\n\"\"\"\n\n LINODE_CLI_VERSION ?= "0.0.0.dev" +# Documentation-related variables +SPHINX_BUILDER ?= html +SPHINX_GENERATED_PATH := ./docs/_generated + .PHONY: install install: check-prerequisites requirements build pip3 install --force dist/*.whl @@ -82,6 +86,18 @@ testall: .PHONY: test test: testunit +.PHONY: clean-docs-commands +clean-docs-commands: + rm -rf "$(SPHINX_GENERATED_PATH)" + +.PHONY: generate-docs +generate-docs-commands: clean-docs-commands + python3 -m linodecli generate-docs "$(SPHINX_GENERATED_PATH)" + +.PHONY: generate-docs +generate-docs: generate-docs-commands + cd docs && make $(SPHINX_BUILDER) + .PHONY: black black: black linodecli tests diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..ed8809902 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/commands/index.rst b/docs/commands/index.rst new file mode 100644 index 000000000..cd6468425 --- /dev/null +++ b/docs/commands/index.rst @@ -0,0 +1,8 @@ +Commands +======== + +.. toctree:: + :maxdepth: 4 + :glob: + + ../_generated/groups/* diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 000000000..34078c399 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,40 @@ +import json +from pathlib import Path + +DOCS_PATH = Path(__file__).parent.resolve() +BUILD_META_PATH = DOCS_PATH / "_generated" / "build_meta.json" + +if not BUILD_META_PATH.is_file(): + raise FileNotFoundError( + "Could not find build_meta file. " + "Was `linode-cli generate-docs` run before attempting to render this documentation?", + ) + +with open(BUILD_META_PATH, "r") as f: + build_meta = json.load(f) + +# Project information +project = "linode-cli" +copyright = "2024, Akamai Technologies Inc." +author = "Akamai Technologies Inc." +version = f"v{build_meta.get('cli_version')} (API v{build_meta.get('api_spec_version')})" + +# General configuration +extensions = ["sphinx_rtd_theme"] +source_suffix = ".rst" +exclude_patterns = [] +highlight_language = "bash" +templates_path = ["templates"] + +# HTML builder configuration +html_logo = "static/logo.svg" +html_favicon = "static/favicon.ico" +html_static_path = ["static"] +html_css_files = [ + "overlay.css" +] + +html_theme = "sphinx_rtd_theme" +html_theme_options = { + "style_nav_header_background": "#009CDE" +} diff --git a/docs/development/guides/01-overview.rst b/docs/development/guides/01-overview.rst new file mode 100644 index 000000000..e0256b0e4 --- /dev/null +++ b/docs/development/guides/01-overview.rst @@ -0,0 +1,150 @@ +.. _development_overview: + +Overview +======== + +The following section outlines the core functions of the Linode CLI. + +OpenAPI Specification Parsing +----------------------------- + +Most Linode CLI commands (excluding `plugin commands `_) +are generated dynamically at build-time from the `Linode OpenAPI Specification `_, +which is also used to generate the `official Linode API documentation `_. + +Each OpenAPI spec endpoint method is parsed into an :code:`OpenAPIOperation` object. +This object includes all necessary request and response arguments to create a command, +stored as :code:`OpenAPIRequestArg` and `OpenAPIResponseAttr` objects respectively. +At runtime, the Linode CLI changes each :code:`OpenAPIRequestArg` to an argparse argument and +each :code:`OpenAPIResponseAttr` to an outputtable column. It can also manage complex structures like +nested objects and lists, resulting in commands and outputs that may not +exactly match the OpenAPI specification. + +OpenAPI Specification Extensions +-------------------------------- + +In order to better support the Linode CLI, the following `Specification Extensions `_ have been added to Linode's OpenAPI spec: + +.. list-table:: + + * - Attribute + - Location + - Purpose + + * - x-linode-cli-action + - method + - The action name for operations under this path. If not present, operationId is used. + + * - x-linode-cli-color + - property + - If present, defines key-value pairs of property value: color. Colors must be one of the `standard colors `_ that accepted by Rich. Must include a default. + + * - x-linode-cli-command + - path + - The command name for operations under this path. If not present, "default" is used. + + * - x-linode-cli-display + - property + - If truthy, displays this as a column in output. If a number, determines the ordering (left to right). + + * - x-linode-cli-format + - property + - Overrides the "format" given in this property for the CLI only. Valid values are :code:`file` and `json`. + + * - x-linode-cli-skip + - path + - If present and truthy, this method will not be available in the CLI. + + * - x-linode-cli-allowed-defaults + - requestBody + - Tells the CLI what configured defaults apply to this request. Valid defaults are "region", "image", "authorized_users", "engine", and "type". + + * - x-linode-cli-nested-list + - content-type + - Tells the CLI to flatten a single object into multiple table rows based on the keys included in this value. Values should be comma-delimited JSON paths, and must all be present on response objects. When used, a new key :code:`_split` is added to each flattened object whose value is the last segment of the JSON path used to generate the flattened object from the source. + + * - x-linode-cli-use-schema + - content-type + - Overrides the normal schema for the object and uses this instead. Especially useful when paired with :code:``x-linode-cli-nested-list``, allowing a schema to describe the flattened object instead of the original object. + + * - x-linode-cli-subtables + - content-type + - Indicates that certain response attributes should be printed in a separate "sub"-table. This allows certain endpoints with nested structures in the response to be displayed correctly. + +Baking +------ + +The "baking" process is run with :code:`make bake`, `make install`, and `make build` targets, +wrapping the :code:`linode-cli bake` command. + +Objects representing each command are serialized into the `data-3` file via the `pickle `_ +package, and are included in release artifacts as a `data file `_. +This enables quick command loading at runtime and eliminates the need for runtime parsing logic. + +Configuration +------------- + +The Linode CLI can be configured using the :code:`linode-cli configure` command, which allows users to +configure the following: + +- A Linode API token + - This can optionally be done using OAuth, see `OAuth Authentication <#oauth-authentication>`_ +- Default values for commonly used fields (e.g. region, image) +- Overrides for the target API URL (hostname, version, scheme, etc.) + +This command serves as an interactive prompt and outputs a configuration file to :code:`~/.config/linode-cli`. +This file is in a simple INI format and can be easily modified manually by users. + +Additionally, multiple users can be created for the CLI which can be designated when running commands using the :code:`--as-user` argument +or using the :code:`default-user` config variable. + +When running a command, the config file is loaded into a :code:`CLIConfig` object stored under the `CLI.config` field. +This object allows various parts of the CLI to access the current user, the configured token, and any other CLI config values by name. + +The logic for the interactive prompt and the logic for storing the CLI configuration can be found in the +:code:`configuration` package. + +OAuth Authentication +-------------------- + +In addition to allowing users to configure a token manually, they can automatically generate a CLI token under their account using +an OAuth workflow. This workflow uses the `Linode OAuth API `_ to generate a temporary token, +which is then used to generate a long-term token stored in the CLI config file. + +The OAuth client ID is hardcoded and references a client under an officially managed Linode account. + +The rough steps of this OAuth workflow are as follows: + +1. The CLI checks whether a browser can be opened. If not, manually prompt the user for a token and skip. +2. Open a local HTTP server on an arbitrary port that exposes :code:`oauth-landing-page.html`. This will also extract the token from the callback. +3. Open the user's browser to the OAuth URL with the hardcoded client ID and the callback URL pointing to the local webserver. +4. Once the user authorizes the OAuth application, they will be redirected to the local webserver where the temporary token will be extracted. +5. With the extracted token, a new token is generated with the default callback and a name similar to :code:`Linode CLI @ localhost`. + +All the logic for OAuth token generation is stored in the :code:`configuration/auth.py` file. + +Outputs +------- + +The Linode CLI uses the `Rich Python package `_ to render tables, colorize text, +and handle other complex terminal output operations. + +Output Overrides +---------------- + +For special cases where the desired output may not be possible using OpenAPI spec extensions alone, developers +can implement special override functions that are given the output JSON and print a custom output to stdout. + +These overrides are specified using the :code:`@output_override` decorator and can be found in the `overrides.py` file. + +Command Completions +------------------- + +The Linode CLI allows users to dynamically generate shell completions for the Bash and Fish shells. +This works by rendering hardcoded templates for each baked/generated command. + +See :code:`completion.py` for more details. + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Setup page `. diff --git a/docs/development/guides/02-setup.rst b/docs/development/guides/02-setup.rst new file mode 100644 index 000000000..b1015313f --- /dev/null +++ b/docs/development/guides/02-setup.rst @@ -0,0 +1,78 @@ +.. _development_setup: + +Setup +===== + +The following guide outlines to the process for setting up the Linode CLI for development. + +Cloning the Repository +---------------------- + +The Linode CLI repository can be cloned locally using the following command:: + + git clone git@github.com:linode/linode-cli.git + +If you do not have an SSH key configured, you can alternatively use the following command:: + + git clone https://github.com/linode/linode-cli.git + +Configuring a VirtualEnv (recommended) +-------------------------------------- + +A virtual env allows you to create virtual Python environment which can prevent potential +Python dependency conflicts. + +To create a VirtualEnv, run the following:: + + python3 -m venv .venv + +To enter the VirtualEnv, run the following command (NOTE: This needs to be run every time you open your shell):: + + source .venv/bin/activate + +Installing Project Dependencies +------------------------------- + +All Linode CLI Python requirements can be installed by running the following command:: + + make requirements + +Building and Installing the Project +----------------------------------- + +The Linode CLI can be built and installed using the :code:`make install` target:: + + make install + +Alternatively you can build but not install the CLI using the :code:`make build` target:: + + make build + +Optionally you can validate that you have installed a local version of the CLI using the :code:`linode-cli --version` command:: + + linode-cli --version + + # Output: + # linode-cli 0.0.0 + # Built from spec version 4.173.0 + # + # The 0.0.0 implies this is a locally built version of the CLI + +Building Using a Custom OpenAPI Specification +--------------------------------------------- + +In some cases, you may want to build the CLI using a custom or modified OpenAPI specification. + +This can be achieved using the :code:`SPEC` Makefile argument, for example:: + + # Download the OpenAPI spec + curl -o openapi.yaml https://raw.githubusercontent.com/linode/linode-api-docs/development/openapi.yaml + + # Make arbitrary changes to the spec + + # Build & install the CLI using the modified spec + make SPEC=$PWD/openapi.yaml install + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Project Skeleton page `. \ No newline at end of file diff --git a/docs/development/guides/03-project-skeleton.rst b/docs/development/guides/03-project-skeleton.rst new file mode 100644 index 000000000..3a52dccbc --- /dev/null +++ b/docs/development/guides/03-project-skeleton.rst @@ -0,0 +1,164 @@ +.. _development_project_skeleton: + +Project Skeleton +================ + +This guide outlines the purpose of each file in the CLI. + +linode-cli +---------- + +Contains all the logic for the `linode-cli` executable. + +.. list-table:: + + * - File + - Purpose + + * - :code:`__init__.py` + - Contains the main entrypoint for the CLI; routes top-level commands to their corresponding functions + + * - :code:`__main__.py` + - Calls the project entrypoint in `__init__.py` + + * - :code:`api_request.py` + - Contains logic for building API request bodies, making API requests, and handling API responses/errors + + * - :code:`arg_helpers.py` + - Contains miscellaneous logic for registering common argparse arguments and loading the OpenAPI spec + + * - :code:`cli.py` + - Contains the `CLI` class, which routes all the logic baking, loading, executing, and outputting generated CLI commands + + * - :code:`completion.py` + - Contains all the logic for generating shell completion files (`linode-cli completion`) + + * - :code:`helpers.py` + - Contains various miscellaneous helpers, especially relating to string manipulation, etc. + + * - :code:`oauth-landing-page.html` + - The page to show users in their browser when the OAuth workflow is complete. + + * - :code:`output.py` + - Contains all the logic for handling generated command outputs, including formatting tables, filtering JSON, etc. + + * - :code:`overrides.py` + - Contains hardcoded output override functions for select CLI commands. + +baked +^^^^^ + +This directory contains logic related to parsing, processing, serializing, and executing the Linode OpenAPI spec. + +.. list-table:: + + * - File + - Purpose + + * - :code:`__init__.py` + - Contains imports for certain classes in this package + + * - :code:`colors.py` + - Contains logic for colorizing strings in CLI outputs (deprecated) + + * - :code:`operation.py` + - Contains the logic to parse an `OpenAPIOperation` from the OpenAPI spec and generate/execute a corresponding argparse parser + + * - :code:`parsing.py` + - Contains various logic related to parsing and translating text between markup languages. + + * - :code:`request.py` + - Contains the `OpenAPIRequest` and `OpenAPIRequestArg` classes + + * - :code:`response.py` + - Contains the `OpenAPIResponse` and `OpenAPIResponseAttr` classes + +configuration +^^^^^^^^^^^^^ + +Contains all logic related to the configuring the Linode CLI. + +.. list-table:: + + * - File + - Purpose + + * - :code:`__init__.py` + - Contains imports for certain classes in this package + + * - :code:`auth.py` + - Contains all the logic for the token generation OAuth workflow + + * - :code:`config.py` + - Contains all the logic for loading, updating, and saving CLI configs + + * - :code:`helpers.py` + - Contains various config-related helpers + +documentation +^^^^^^^^^^^^^ + +Contains the logic and templates to generate documentation for the Linode CLI. + +.. list-table:: + + * - File + - Purpose + + * - :code:`templates` + - Contains the template files used to dynamically generate documentation pages + + * - :code:`__init__.py` + - Contains imports for certain classes in this package + + * - :code:`generator.py` + - Contains the logic to render and write documentation files + + * - :code:`template_data.py` + - Contains all dataclasses used to render the documentation templates + +plugins +^^^^^^^ + +Contains the default plugins and plugin SDK for this project. + +.. list-table:: + + * - File + - Purpose + + * - :code:`__init__.py` + - Contains imports for certain classes in this package + + * - :code:`plugins.py` + - Contains the shared wrapper that allows plugins to access CLI functionality + +docs +---- + +Contains the Sphinx configuration used to render the Linode CLI's documentation. + +.. list-table:: + + * - File + - Purpose + + * - :code:`commands` + - Contains non-generated documentation templates for the Linode CLI's commands. + + * - :code:`development` + - Contains documentation templates for Linode CLI's development guide. + + * - :code:`conf.py` + - Contains the Sphinx configuration for the Linode CLI's documentation + + * - :code:`index.rst` + - The index/root document for the Linode CLI's documentation. + + * - :code:`Makefile` + - Contains targets to render the documentation for this project + + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Testing page `. diff --git a/docs/development/guides/04-testing.rst b/docs/development/guides/04-testing.rst new file mode 100644 index 000000000..6c55849bd --- /dev/null +++ b/docs/development/guides/04-testing.rst @@ -0,0 +1,34 @@ +.. _development_testing: + +Testing +======= + +This page gives an overview of how to run the various test suites for the Linode CLI. + +Before running any tests, built and installed the Linode CLI with your changes using :code:`make install`. + +Running Unit Tests +------------------ + +Unit tests can be run using the :code:`make testunit` Makefile target. + +Running Integration Tests +------------------------- + +Running the tests locally is simple. The only requirements are that you export Linode API token as :code:`LINODE_CLI_TOKEN`:: + + export LINODE_CLI_TOKEN="your_token" + +More information on Managing Linode API tokens can be found in our [API Token Docs](https://www.linode.com/docs/products/tools/api/guides/manage-api-tokens/). + +In order to run the full integration test, run:: + + make testint + +To run specific test package, use environment variable :code:`INTEGRATION_TEST_PATH` with `testint` command:: + + make INTEGRATION_TEST_PATH="cli" testint + +Lastly, to run specific test case, use environment variables :code:`TEST_CASE` with `testint` command:: + + make TEST_CASE=test_help_page_for_non_aliased_actions testint diff --git a/docs/development/index.rst b/docs/development/index.rst new file mode 100644 index 000000000..a3752b770 --- /dev/null +++ b/docs/development/index.rst @@ -0,0 +1,15 @@ +Development +=========== + +This section will help you get started developing against and contributing to the Linode CLI. + +.. toctree:: + :maxdepth: 3 + :glob: + + guides/* + +Contributing +------------ + +Once you're ready to contribute a change to the project, please refer to our `Contributing Guide `_. \ No newline at end of file diff --git a/docs/general/guides/01-installation.rst b/docs/general/guides/01-installation.rst new file mode 100644 index 000000000..6a08476d2 --- /dev/null +++ b/docs/general/guides/01-installation.rst @@ -0,0 +1,93 @@ +Installation +============ + +This document outlines the officially supported installation methods for the Linode CLI. + +PyPi +---- + +The Linode CLI is automatically released to PyPI and can be installed using `pip`:: + + python3 -m pip install linode-cli + +The following can be used to upgrade an existing installation of the Linode CLI:: + + pip3 install linode-cli --upgrade + +Docker +------ + +The Linode CLI is also officially distributed as a `Docker Image `_. + +Authenticating with a Personal Access Token +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following command runs the `linodes list` command in a Docker container +using an existing `Personal Access Token `_:: + + docker run --rm -it -e LINODE_CLI_TOKEN=$LINODE_TOKEN linode/cli:latest linodes list + +Authenticating with an Existing Configuration +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following command runs the `linodes list` command in a Docker container +using an existing Linode CLI configuration file:: + + docker run --rm -it -v $HOME/.config/linode-cli:/home/cli/.config/linode-cli linode/cli:latest linodes list + +GitHub Actions +-------------- + +The Linode CLI can automatically be installed in a GitHub Actions runner environment using the +`Setup Linode CLI Action `_: + +.. code-block:: yaml + + - name: Install the Linode CLI + uses: linode/action-linode-cli@v1 + with: + token: ${{ secrets.LINODE_TOKEN }} + + +Community Distributions +----------------------- + +The Linode CLI is available through unofficial channels thanks to our awesome community! +These distributions are not included in release testing. + +Homebrew +^^^^^^^^ + +.. code-block:: + + brew install linode-cli + brew upgrade linode-cli + +Building from Source +-------------------- + +In order to successfully build the CLI, your system will require the following: + +- The `make` command +- `python3` +- `pip3` (to install project dependencies) + +Before attempting a build, ensure all necessary dependencies have been installed:: + + make requirements + +Once everything is set up, you can initiate a build like so:: + + make build + +If desired, you may pass in :code:`SPEC=/path/to/openapi-spec` when running :code:`build` +or :code:`install`. This can be a URL or a path to a local spec, and that spec will +be used when generating the CLI. A yaml or json file is accepted. + +To install the package as part of the build process, use this command:: + + make install + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Configuration page `. diff --git a/wiki/Configuration.md b/docs/general/guides/02-configuration.rst similarity index 58% rename from wiki/Configuration.md rename to docs/general/guides/02-configuration.rst index 879dc6d18..09ef12296 100644 --- a/wiki/Configuration.md +++ b/docs/general/guides/02-configuration.rst @@ -1,90 +1,98 @@ -# Configuration +.. _general_configuration: + +Configuration +============= The first time the CLI runs, it will prompt you to configure it. The CLI defaults to using web-based configuration, which is fast and convenient for users who have access to a browser. To manually configure the CLI or reconfigure it if your token expires, you can -run the `configure` command:: -```bash -linode-cli configure -``` +run the :code:`configure` command:: + + linode-cli configure If you prefer to provide a token directly through the terminal, possibly because you don't have access to a browser where you're configuring the CLI, pass the -`--token` flag to the configure command as shown:: -```bash -linode-cli configure --token -``` +:code:`--token` flag to the configure command as shown:: + + linode-cli configure --token When configuring multiple users using web-based configuration, you may need to log out of cloud.linode.com before configuring a second user. -## Environment Variables +Environment Variables +^^^^^^^^^^^^^^^^^^^^^ If you prefer, you may store your token in an environment variable named -`LINODE_CLI_TOKEN` instead of using the configuration file. Doing so allows you -to bypass the initial configuration, and subsequent calls to `linode-cli configure` +:code:`LINODE_CLI_TOKEN` instead of using the configuration file. Doing so allows you +to bypass the initial configuration, and subsequent calls to :code:`linode-cli configure` will allow you to set defaults without having to set a token. Be aware that if the environment variable should be unset, the Linode CLI will stop working until it is set again or the CLI is reconfigured with a token. You may also use environment variables to store your Object Storage Keys for -the `obj` plugin that ships with the CLI. To do so, simply set -`LINODE_CLI_OBJ_ACCESS_KEY` and `LINODE_CLI_OBJ_SECRET_KEY` to the +the :code:`obj` plugin that ships with the CLI. To do so, simply set +:code:`LINODE_CLI_OBJ_ACCESS_KEY` and :code:`LINODE_CLI_OBJ_SECRET_KEY` to the appropriate values. This allows using Linode Object Storage through the CLI without having a configuration file, which is desirable in some situations. -You may also specify the path to a custom Certificate Authority file using the `LINODE_CLI_CA` +You may also specify the path to a custom Certificate Authority file using the :code:`LINODE_CLI_CA` environment variable. -## Configurable API URL +Configurable API URL +^^^^^^^^^^^^^^^^^^^^ In some cases you may want to run linode-cli against a non-default Linode API URL. This can be done using the following environment variables to override certain segments of the target API URL. -* `LINODE_CLI_API_HOST` - The host of the Linode API instance (e.g. `api.linode.com`) +* :code:`LINODE_CLI_API_HOST` - The host of the Linode API instance (e.g. :code:`api.linode.com`) -* `LINODE_CLI_API_VERSION` - The Linode API version to use (e.g. `v4beta`) +* :code:`LINODE_CLI_API_VERSION` - The Linode API version to use (e.g. :code:`v4beta`) -* `LINODE_CLI_API_SCHEME` - The request scheme to use (e.g. `https`) +* :code:`LINODE_CLI_API_SCHEME` - The request scheme to use (e.g. :code:`https`) -Alternatively, these values can be configured per-user using the ``linode-cli configure`` command. +Alternatively, these values can be configured per-user using the :code:`linode-cli configure` command. -## Multiple Users +Multiple Users +^^^^^^^^^^^^^^ If you use the Linode CLI to manage multiple Linode accounts, you may configure -additional users using the ``linode-cli configure`` command. The CLI will automatically +additional users using the :code:`linode-cli configure` command. The CLI will automatically detect that a new user is being configured based on the token given. -## Displaying Configured Users +Displaying Configured Users +^^^^^^^^^^^^^^^^^^^^^^^^^^^ To see what users are configured, simply run the following:: -```bash -linode-cli show-users -``` + + linode-cli show-users The user who is currently active will be indicated by an asterisk. -## Changing the Active User +Changing the Active User +^^^^^^^^^^^^^^^^^^^^^^^^ You may change the active user for all requests as follows:: -```bash -linode-cli set-user USERNAME -``` + + linode-cli set-user USERNAME Subsequent CLI commands will be executed as that user by default. Should you wish to execute a single request as a different user, you can supply -the `--as-user` argument to specify the username you wish to act as for that +the :code:`--as-user` argument to specify the username you wish to act as for that command. This *will not* change the active user. -## Removing Configured Users +Removing Configured Users +^^^^^^^^^^^^^^^^^^^^^^^^^ To remove a user from you previously configured, run:: -```bash -linode-cli remove-user USERNAME -``` + + linode-cli remove-user USERNAME Once a user is removed, they will need to be reconfigured if you wish to use the CLI for them again. + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Usage page `. diff --git a/docs/general/guides/03-usage.rst b/docs/general/guides/03-usage.rst new file mode 100644 index 000000000..f125a6626 --- /dev/null +++ b/docs/general/guides/03-usage.rst @@ -0,0 +1,176 @@ +.. _general_usage: + +Usage +===== + +The Linode CLI is invoked with the :code:`linode-cli`, +or with either of its two aliases available: :code:`linode` and :code:`lin`. + +The CLI accepts two primary arguments, *command* and *action*:: + + linode-cli + +*command* is the part of the CLI you are interacting with, for example "linodes". +You can see a list of all available commands by using :code:`--help`:: + + linode-cli --help + + +*action* is the action you want to perform on a given command, for example "list". +You can see a list of all available actions for a command with the :code:`--help` for +that command:: + + linode-cli linodes --help + +Some actions don't require any parameters, but many do. To see details on how +to invoke a specific action, use :code:`--help` for that action:: + + linode-cli linodes create --help + +The first time you invoke the CLI, you will be asked to configure (see +"Configuration" below for details), and optionally select some default values +for "region," "image," and "type." If you configure these defaults, you may +omit them as parameters to actions and the default value will be used. + +Common Operations +----------------- + +List Linodes:: + + linode-cli linodes list + +List Linodes in a Region:: + + linode-cli linodes list --region us-east + +Create a Linode:: + + linode-cli linodes create --type g5-standard-2 --region us-east --image linode/debian9 --label cli-1 --root_pass + +Create a Linode using default settings:: + + linode-cli linodes create --label cli-2 --root_pass + +Reboot a Linode:: + + linode-cli linodes reboot 12345 + +View available Linode types:: + + linode-cli linodes types + +View your Volumes:: + + linode-cli volumes list + +View your Domains:: + + linode-cli domains list + +View records for a single Domain:: + + linode-cli domains records-list 12345 + +View your user:: + + linode-cli profile view + +Specifying List Arguments +------------------------- + +When running certain commands, you may need to specify multiple values for a list +argument. This can be done by specifying the argument multiple times for each +value in the list. For example, to create a Linode with multiple :code:`tags` +you can execute the following:: + + linode-cli linodes create --region us-east --type g6-nanode-1 --tags tag1 --tags tag2 + +Lists consisting of nested structures can also be expressed through the command line. +Duplicated attribute will signal a different object. +For example, to create a Linode with a public interface on :code:`eth0` and a VLAN interface +on :code:`eth1` you can execute the following:: + + linode-cli linodes create \ + --region us-east --type g6-nanode-1 --image linode/ubuntu22.04 \ + --root_pass "myr00tp4ss123" \ + # The first interface (index 0) is defined with the public purpose + --interfaces.purpose public \ + # The second interface (index 1) is defined with the vlan purpose. + # The duplicate `interfaces.purpose` here tells the CLI to start building a new interface object. + --interfaces.purpose vlan --interfaces.label my-vlan + +Specifying Nested Arguments +--------------------------- + +When running certain commands, you may need to specify an argument that is nested +in another field. These arguments can be specified using a :code:`.` delimited path to +the argument. For example, to create a firewall with an inbound policy of :code:`DROP` +and an outbound policy of :code:`ACCEPT`, you can execute the following:: + + linode-cli firewalls create --label example-firewall --rules.outbound_policy ACCEPT --rules.inbound_policy DROP + +Special Arguments +----------------- + +In some cases, certain values for arguments may have unique functionality. + +Null Values +^^^^^^^^^^^ + +Arguments marked as nullable can be passed the value :code:`null` to send an explicit null value to the Linode API:: + + linode-cli networking ip-update --rdns null 127.0.0.1 + +Empty Lists +^^^^^^^^^^^ + +List arguments can be passed the value :code:`[]` to send an explicit empty list value to the Linode API:: + + linode-cli networking ip-share --linode_id 12345 --ips [] + +Suppressing Defaults +-------------------- + +If you configured default values for :code:`image`, :code:`authorized_users`, :code:`region`, +database :code:`engine`, and Linode :code:`type`, they will be sent for all requests that accept them +if you do not specify a different value. If you want to send a request *without* these +arguments, you must invoke the CLI with the :code:`--no-defaults` option. + +For example, to create a Linode with no :code:`image` after a default Image has been +configured, you would do this:: + + linode-cli linodes create --region us-east --type g5-standard-2 --no-defaults + +Suppressing Warnings +-------------------- + +In some situations, like when the CLI is out of date, it will generate a warning +in addition to its normal output. If these warnings can interfere with your +scripts or you otherwise want them disabled, simply add the :code:`--suppress-warnings` +flag to prevent them from being emitted. + +## Suppressing Retries + +Sometimes the API responds with a error that can be ignored. For example a timeout +or nginx response that can't be parsed correctly, by default the CLI will retry +calls on these errors we've identified. If you'd like to disable this behavior for +any reason use the :code:`--no-retry` flag. + +Shell Completion +---------------- + +To generate a completion file for a given shell type, use the :code:`completion` command; +for example to generate completions for bash run:: + + linode-cli completion bash + +The output of this command is suitable to be included in the relevant completion +files to enable command completion on your shell. + +This command currently supports completions bash and fish shells. + +Use :code:`bashcompinit` on zsh with the bash completions for support on zsh shells. + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Output page `. diff --git a/wiki/Output.md b/docs/general/guides/04-output.rst similarity index 53% rename from wiki/Output.md rename to docs/general/guides/04-output.rst index 52db17fc7..69bf27e12 100644 --- a/wiki/Output.md +++ b/docs/general/guides/04-output.rst @@ -1,58 +1,62 @@ -# Customizing Output +.. _general_output: -## Changing Output Fields +Customizing Output +================== + +Changing Output Fields +---------------------- By default, the CLI displays on some pre-selected fields for a given type of response. If you want to see everything, just ask:: -```bash -linode-cli linodes list --all -``` -Using `--all` will cause the CLI to display all returned columns of output. + linode-cli linodes list --all + +Using :code:`--all` will cause the CLI to display all returned columns of output. Note that this will probably be hard to read on normal-sized screens for most actions. If you want even finer control over your output, you can request specific columns be displayed:: -```bash -linode-cli linodes list --format 'id,region,status,disk,memory,vcpus,transfer' -``` + + linode-cli linodes list --format 'id,region,status,disk,memory,vcpus,transfer' This will show some identifying information about your Linode as well as the resources it has access to. Some of these fields would be hidden by default - that's ok. If you ask for a field, it'll be displayed. -## Output Formatting +Output Formatting +----------------- While the CLI by default outputs human-readable tables of data, you can use the CLI to generate output that is easier to process. -## Machine Readable Output +Machine Readable Output +----------------------- To get more machine-readable output, simply request it:: -```bash -linode-cli linodes list --text -``` + + linode-cli linodes list --text If a tab is a bad delimiter, you can configure that as well:: -```bash -linode-cli linodes list --text --delimiter ';' -``` + + linode-cli linodes list --text --delimiter ';' You may also disable header rows (in any output format):: -```bash -linode-cli linodes list --no-headers --text -``` -## JSON Output + linode-cli linodes list --no-headers --text + +JSON Output +----------- To get JSON output from the CLI, simple request it:: -```bash -linode-cli linodes list --json --all -``` -While the `--all` is optional, you probably want to see all output fields in + linode-cli linodes list --json --all + +While the :code:`--all` is optional, you probably want to see all output fields in your JSON output. If you want your JSON pretty-printed, we can do that too:: -```bash -linode-cli linodes list --json --pretty --all -``` + + linode-cli linodes list --json --pretty --all + +.. rubric:: Next Steps + +To continue to the next step of this guide, continue to the :ref:`Plugins page `. diff --git a/wiki/Plugins.md b/docs/general/guides/05-plugins.rst similarity index 63% rename from wiki/Plugins.md rename to docs/general/guides/05-plugins.rst index 00e299fd3..2ae22135d 100644 --- a/wiki/Plugins.md +++ b/docs/general/guides/05-plugins.rst @@ -1,28 +1,31 @@ -# Plugins +.. _general_plugins: + +Plugins +======= The Linode CLI allows its features to be expanded with plugins. Some official plugins come bundled with the CLI and are documented above. Additionally, anyone can write and distribute plugins for the CLI - these are called Third Party Plugins. To register a Third Party Plugin, use the following command:: -```bash -linode-cli register-plugin PLUGIN_MODULE_NAME -``` + + linode-cli register-plugin PLUGIN_MODULE_NAME Plugins should give the exact command required to register them. Once registered, the command to invoke the Third Party Plugin will be printed, and -it will appear in the plugin list when invoking `linode-cli --help`. +it will appear in the plugin list when invoking :code:`linode-cli --help`. To remove a previously registered plugin, use the following command:: -```bash -linode-cli remove-plugin PLUGIN_NAME -``` + + linode-cli remove-plugin PLUGIN_NAME This command accepts the name used to invoke the plugin in the CLI as it appears -in `linode-cli --help`, which may not be the same as the module name used to +in :code:`linode-cli --help`, which may not be the same as the module name used to register it. -## Developing Plugins +Developing Plugins +------------------ -For information on how To write your own Third Party Plugin, see the [Plugins documentation](https://github.com/linode/linode-cli/blob/main/linodecli/plugins/README.md) +For information on how To write your own Third Party Plugin, see the +:ref:`Plugins documentation `. diff --git a/docs/general/index.rst b/docs/general/index.rst new file mode 100644 index 000000000..d987881e0 --- /dev/null +++ b/docs/general/index.rst @@ -0,0 +1,9 @@ +General +======= + +This section details general information related to the installation, usage, and configuration of the Linode CLI. + +.. toctree:: + :glob: + + guides/* diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 000000000..21e9b4f67 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,21 @@ +linode-cli Documentation +======================== + +.. image:: static/demo.gif + :alt: Linode CLI Demo + +Welcome to the `linode-cli` documentation! + +For installation instructions and usage guides, please +refer to the sidebar of this page or the Table of Contents below. + +Table of Contents +----------------- + +.. toctree:: + :maxdepth: 2 + + general/index.rst + development/index.rst + plugins/index.rst + commands/index.rst \ No newline at end of file diff --git a/docs/plugins/development.rst b/docs/plugins/development.rst new file mode 100644 index 000000000..f3434cb31 --- /dev/null +++ b/docs/plugins/development.rst @@ -0,0 +1,147 @@ +Development +=========== + +The Linode CLI supports embedded plugins, features that are hard-coded (instead +of generated as the rest of the CLI is) but are accessible directly through the +CLI as other features are. All plugins are found in this directory. + +Creating a Plugin +----------------- + +To create a plugin, simply drop a new python file into this directory or write a +Python module that presents the interface described below. If the +plugin is a Python module, make sure the :code:`call` method is in the :code:`__init__.py` +file in the root of the module. + +Plugins in this directory are called "Internal Plugins," and must meet the +following conditions: + +* Its name must be unique, both with the other plugins and with all commands + offered through the generated CLI +* Its name must not contain special characters, and should be easily to enter + on the command line +* It must contain a :code:`call(args, context)` function for invocation +* It must support a :code:`--help` command as all other CLI commands do. + +Plugins that are installed separately and registered with the :code:`register-plugin` +command are called "Third Party Plugins," and must meet the following +conditions: + +* Its name must be unique, both with the internal plugins and all CLI operations +* It must contain a :code:`call(args, context)` function for invocation +* It must contain a :code:`PLUGIN_NAME` constant whose value is a string that does not + contain special characters, and should be easy to enter on the command line. +* It should support a `--help` command as all other CLI commands do. + +The Plugin Interface +-------------------- + +All plugins are either an individual python file or a Python module +that reside in this directory or installed separately. Plugins must have one function, :code:`call`, that +matches the following signature: + +.. code-block:: python + + def call(args, context): + """ + This is the function used to invoke the plugin. It will receive the remainder + of sys.argv after the plugin's name, and a context of user defaults and config + settings. + """ + +The PluginContext +^^^^^^^^^^^^^^^^^ + +The :code:`PluginContext` class, passed as :code:`context` to the :code:`call` function, includes +all information the plugin is given during invocation. This includes the following: + +* :code:`token` - The Personal Access Token registered with the CLI to make requests. +* :code:`client` - The CLI Client object that can make authenticated requests on behalf + of the acting user. This is preferrable to using `requests` or another library + directly (see below). + +.. rubric:: CLI Client + +The CLI Client provided as :code:`context.client` can make authenticated API calls on +behalf of the user using the provided :code:`call_operation` method. This method is +invoked with a command and an action, and executes the given CLI command as if +it were entered into the command line, returning the resulting status code and +JSON data. + +Configuration +------------- + +Plugins can access the CLI's configuration through the CLI Client mentioned above. +Plugins are allowed to: + +* Read values from the current user's config +* Read and write their own values to the current user's config + +Any other operation is not supported and may break without notice. + +Methods +^^^^^^^ + +The :code:`Configuration` class provides the following methods for plugins to use: + +**get_value(key)** Returns the value the current user has set for this key, or :code:`None` +if the key does not exist. Currently supported keys are :code:`region`, :code:`type`, and :code:`image`. + +**plugin_set_value(key, value)** Sets a value in the user's config for this plugin. +Plugins can safely set values for any key, and they are namespaced away from other +config keys. + +**plugin_get_value(key)** Returns the value this plugin previously set for the given +key, or :code:`None` if not set. Plugins should assume they are not configured if they +receive :code:`None` when getting a value with this method. + +**write_config()** Writes config changes to disk. This is required to save changes +after calling :code:`plugin_set_value` above. + +Sample Code +^^^^^^^^^^^ + +The following code manipulates and reads from the config in a plugin: + +.. code-block:: python + + def call(args, context): + # get a value from the user's config + default_region = context.client.config.get_value('region') + + # check if we set a value previously + our_value = context.client.config.plugin_get_value('configured') + + if our_value is None: + # plugin not configured - do configuration here + context.client.config.plugin_set_value('configured', 'yes') + + # save the config so changes take effect + context.client.config.write_config() + + # normal plugin code + +Development +----------- + +To develop a plugin, simply create a python source file in this directory that +has a :code:`call` function as described above. To test, simply build the CLI as +normal (via :code:`make install`) or simply by running :code:`./setup.py install` in the +root directory of the project (this installs the code without generating new +baked data, and will only work if you've installed the CLI via :code:`make install` +at least once, however it's a lot faster). + +To develop a third party plugin, simply create and install your module and register +it to the CLI. As long as the :code:`PLUGIN_NAME` doesn't change, updated installations +should invoke the new code. + +Examples +^^^^^^^^ + +This directory contains two example plugins, :code:`echo.py.example` and +:code:`regionstats.py.example`. To run these, simply remove the :code:`.example` at the end +of the file and build the CLI as described above. + +`This directory `_ +contains an example Third Party Plugin module. This module is installable and +can be registered to the CLI. diff --git a/docs/plugins/index.rst b/docs/plugins/index.rst new file mode 100644 index 000000000..5c00558a6 --- /dev/null +++ b/docs/plugins/index.rst @@ -0,0 +1,13 @@ +.. _plugins: + +Plugins +======= + +This section details general information related to the usage and development of Linode CLI plugins. + +.. toctree:: + :maxdepth: 2 + :glob: + + development + plugins/* diff --git a/docs/static/demo.gif b/docs/static/demo.gif new file mode 100644 index 0000000000000000000000000000000000000000..80a408ae98c7f4749ab67a5aeb1dedc66cef265f GIT binary patch literal 180306 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%0D0!Roeb5K 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 JAM6GJ06TrRQwsn9 literal 0 HcmV?d00001 diff --git a/docs/static/favicon.ico b/docs/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f2c712fdba4fd4e394f91f7eb8e80de2be06d3cd GIT binary patch literal 16958 zcmdskMS<;87oGE%yi%cz2Fj>~r`cMXvy^uH`G&2;; zGDE|n5Gp7VlL&j6QhFgl3(Sm&%`Kx+nzCr9X>Y%0=AO&(diUNl)83=kmH$5Hp7Xr@ z&pC7Mxo7U`I2ryG3J$-|cg9@nIA=SKGX_xQ6oJ&&erOv!ppJUQiTS;MgEJ6}2a~|< z;4ZKfbe@=ul8p+lAz(Im2J8YyfE$9H$!22DJKS2qo#2BIo;vsMXkQL4wU=FTk>DX? zy%rn=I?rJFW7?-Cmx*1^a2WtrgDMDe)vx!_KFMx&$wq_EEbvzh?|*1tm~19?y~C$J z*dD`M#$MLEVRo}iHX3{;fWtta+hOHZ$!22TJDhJb;4OVI$9{InMugJ>L+&>vn~8nz z@SbPLeTx0;l8p%OX@=ZS#W_C??s4~Z`Mj@4b`9G0Zw@X?lK2X)#uhv4EVoicU0^|gSY8@zF;RKyHVhOz+miOx0{unXz;$n zfV+I|Pq}@L^f0_WG~mD6&S=<;0&h8&)bH!Pl^5I1%uY18KWxZ&?sDR$)ysCdf=ZC(W`=xsSOa8LYp9&PmC^>cQQ!eX z{-YIt&rbSky{b#2B>x-1W)L;*(sl^6DUOuYK5@0GOQZC7yn~G6zeneX{wB{R)zAKL zcogjQxJ32AjsXANp3PdlK5b<<$Qu5w0sk$E8@lqH&(EICR#l%y35O@aL61w+_`jg| zp*sS|_d25gg{n`ZB>!gkkM+0_7jYzb(Y(q zoKMJmH-CdcQF+iF_r8{J^v^#iUjr0xUCxb)W223{WUepM@{4`P4Bdv#ztBGobZaqG zAN)q$xi)wPV-R-`koPIeK;?6NP%rEn{f5s!v3W|1qvDA??o5cf#b8NT?Eh1T&n&nB zYynlE=P|hv-`JJ{_PQ@s_Rqi3ofx6NPLGY=6+q^O_}Kt12dC>gre*9#gH9lv4+E8( zlJaae-qfGc!^ZUckDE1{H$vj8JeDdwCDDCO)0bz5_kp}0y9CSuw}R_{jOh%}0pznO zI&XtRK=}`oFVo&szedbuxH9_dJv+rU zOv?N_Px+#}!oWuS$eKMLWRz`RO8kxm^0`nsuW80V_IorR%2!YZ&qZG{uu(o_Uatig zH=F11O9a1s(j3xM*md<8)d8HL2Nbx;UIhKkzgQb z0kYQ=*#_j^A$d&(cY|laUZDKw@<-}JpLtC9iw^eFdhxBtk#dLblj{wJc0oVt`d{pi z0O^vF1_XWW| z7=!Is7W-jiSpI!c2M5#l-#dfxuG+v5Mu%ed*%qv)8oDu#jZbC1cGO0 zLEA>IW$l|4?C&J6iPs9Yg19_)p%c3PQZIi4xen|Daenl6Srp;J%K3viXDK89?^#1uzqIfW<)8wthDAbzQfT;}<{0x~w|wwac+;k~ZO53oo|%$8PQKRO;~*>T zz4ABO!59aggUA6~#{J6yt zPR=d2yT#hqH0^GwcHEJ7yRt?6EOX15691zEp`5b#!{I{?7B1uB)cUlT>yniGaZ}@{ N#?>v>8Mzga{{fCcRWkqp literal 0 HcmV?d00001 diff --git a/docs/static/logo.svg b/docs/static/logo.svg new file mode 100644 index 000000000..1edc0c288 --- /dev/null +++ b/docs/static/logo.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docs/static/overlay.css b/docs/static/overlay.css new file mode 100644 index 000000000..1f53836d6 --- /dev/null +++ b/docs/static/overlay.css @@ -0,0 +1,37 @@ +/* Hack to force wrapping in table cells. */ +table { + width: 100% !important; +} + +tr { + width: 100% !important; +} + +td { + word-wrap: break-word !important; + white-space: normal !important; +} + +/* Make the content area a bit larger than default. */ +.wy-nav-content { + max-width: 1000px !important; +} + +/* Make the logo a bit larger than default */ +.logo { + width: 150px !important; +} + +/* Custom formatting for actions */ +.action-subheading { + margin-bottom: 4px !important; +} + +.action-subheading-description { + font-size: 90% !important; + margin-bottom: 12px !important; +} + +.action-argument-required { + color: red !important; +} diff --git a/linodecli/__init__.py b/linodecli/__init__.py index aa7331b40..931feb318 100755 --- a/linodecli/__init__.py +++ b/linodecli/__init__.py @@ -24,6 +24,7 @@ from .cli import CLI from .completion import get_completions from .configuration import ENV_TOKEN_NAME +from .documentation.generator import DocumentationGenerator from .help_pages import ( HELP_TOPICS, print_help_action, @@ -100,7 +101,7 @@ def main(): # pylint: disable=too-many-branches,too-many-statements # handle a bake - this is used to parse a spec and bake it as a pickle if parsed.command == "bake": if parsed.action is None: - print("No spec provided, cannot bake") + print("No spec provided, cannot bake.", file=sys.stderr) sys.exit(ExitCodes.ARGUMENT_ERROR) bake_command(cli, parsed.action) sys.exit(ExitCodes.SUCCESS) @@ -108,6 +109,17 @@ def main(): # pylint: disable=too-many-branches,too-many-statements # if not spec was found and we weren't baking, we're doomed sys.exit(ExitCodes.ARGUMENT_ERROR) + if parsed.command == "generate-docs": + if parsed.action is None: + print( + "No directory provided, cannot generate documentation.", + file=sys.stderr, + ) + sys.exit(ExitCodes.ARGUMENT_ERROR) + + DocumentationGenerator().generate(cli, output_directory=parsed.action) + sys.exit(ExitCodes.SUCCESS) + if parsed.command == "register-plugin": if parsed.action is None: print("register-plugin requires a module name!") diff --git a/linodecli/baked/operation.py b/linodecli/baked/operation.py index 1494792cc..35210e85d 100644 --- a/linodecli/baked/operation.py +++ b/linodecli/baked/operation.py @@ -17,6 +17,7 @@ import openapi3.paths from openapi3.paths import Operation, Parameter +from linodecli.baked.parsing import process_arg_description from linodecli.baked.request import OpenAPIFilteringRequest, OpenAPIRequest from linodecli.baked.response import OpenAPIResponse from linodecli.exit_codes import ExitCodes @@ -285,6 +286,9 @@ def __init__(self, parameter: openapi3.paths.Parameter): """ self.name = parameter.name self.type = parameter.schema.type + self.description_rich, self.description = process_arg_description( + parameter.description or "" + ) def __repr__(self): return f"" @@ -357,7 +361,7 @@ def __init__( self.action = action self.summary = operation.summary - self.description = operation.description.split(".")[0] + self.description = operation.description.split(".")[0] + "." # The apiVersion attribute should not be specified as a positional argument self.params = [ @@ -387,6 +391,8 @@ def __init__( else [] ) + self.deprecated = operation.deprecated + @property def args(self): """ @@ -584,6 +590,7 @@ def _add_args_post_put( arg_type = ( arg.item_type if arg.datatype == "array" else arg.datatype ) + arg_type_handler = TYPES[arg_type] if arg.nullable: @@ -781,29 +788,43 @@ def parse_args(self, args: Any) -> argparse.Namespace: :rtype: Namespace """ - # build an argparse - parser = argparse.ArgumentParser( + parser, list_items = self._build_parser() + + parsed = parser.parse_args(args) + + if self.method in ("post", "put"): + self._validate_parent_child_conflicts(parsed) + + return self._handle_list_items(list_items, parsed) + + def _build_parser( + self, + ) -> Tuple[argparse.ArgumentParser, List[Tuple[str, str]]]: + """ + Builds and returns an argument parser for this operation. + + :returns: A tuple containing the new argument parser and a list of tuples, each + representing a single list argument. + """ + + result = argparse.ArgumentParser( prog=f"linode-cli {self.command} {self.action}", description=self.summary, ) + for param in self.params: - parser.add_argument( + result.add_argument( param.name, metavar=param.name, type=TYPES[param.type] ) list_items = [] if self.method == "get": - self._add_args_filter(parser) + self._add_args_filter(result) elif self.method in ("post", "put"): - list_items = self._add_args_post_put(parser) + list_items = self._add_args_post_put(result) - parsed = parser.parse_args(args) - - if self.method in ("post", "put"): - self._validate_parent_child_conflicts(parsed) - - return self._handle_list_items(list_items, parsed) + return result, list_items @staticmethod def _resolve_operation_docs_url_legacy( diff --git a/linodecli/baked/parsing.py b/linodecli/baked/parsing.py index 5125e45dc..b03f46c22 100644 --- a/linodecli/baked/parsing.py +++ b/linodecli/baked/parsing.py @@ -176,9 +176,10 @@ def process_arg_description(description: str) -> Tuple[str, str]: result = strip_techdocs_prefixes(result) result = result.replace("\n", " ").replace("\r", " ") - description, links = extract_markdown_links(result) + # NOTE: Links should only be separated from Rich Markdown links + result_no_links, links = extract_markdown_links(result) if len(links) > 0: - description += f" See: {'; '.join(links)}" + result_no_links += f" See: {'; '.join(links)}" - return unescape(markdown_to_rich_markup(description)), unescape(description) + return unescape(markdown_to_rich_markup(result_no_links)), unescape(result) diff --git a/linodecli/baked/response.py b/linodecli/baked/response.py index 323c3ddef..0a6409f93 100644 --- a/linodecli/baked/response.py +++ b/linodecli/baked/response.py @@ -4,6 +4,8 @@ from openapi3.paths import MediaType +from linodecli.baked.parsing import process_arg_description + def _is_paginated(response): """ @@ -52,8 +54,10 @@ def __init__(self, name, schema, prefix=None, nested_list_depth=0): self.nested_list_depth = nested_list_depth #: The description of this argument, for help display. Only used for filterable attributes. - self.description = ( - schema.description.split(".")[0] if schema.description else "" + self.description_rich, self.description = ( + process_arg_description(schema.description) + if schema.description + else ("", "") ) #: No response model fields are required. This is only used for filterable attributes. diff --git a/linodecli/documentation/__init__.py b/linodecli/documentation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/linodecli/documentation/generator.py b/linodecli/documentation/generator.py new file mode 100644 index 000000000..02c8a982d --- /dev/null +++ b/linodecli/documentation/generator.py @@ -0,0 +1,59 @@ +import json +from dataclasses import asdict +from pathlib import Path + +from jinja2 import Environment, PackageLoader, select_autoescape + +from linodecli import CLI +from linodecli.documentation.template_data import BuildMeta, Root + +TEMPLATE_NAME_GROUP = "group.rst.j2" + +OUTPUT_PATH_BUILD_META = "build_meta.json" +OUTPUT_PATH_GROUP_FORMAT = "groups/{name}.rst" + + +class DocumentationGenerator: + def __init__(self): + self._template_env = Environment( + loader=PackageLoader("linodecli.documentation", "templates"), + autoescape=select_autoescape(), + trim_blocks=True, + lstrip_blocks=True, + ) + + def generate(self, cli: CLI, output_directory: str = "./docs/_generated"): + """ + Generates the relevant documentation for the given CLI + to the given `output_directory`. + + :param cli: The main Linode CLI object to generate documentation for. + :param output_directory: The parent directory to generate the documentation under. + """ + + build_meta = BuildMeta( + cli_version=cli.version, + api_spec_version=cli.spec_version, + ) + + root_data = Root.from_cli(cli) + + output_path = Path(output_directory) + output_path.mkdir(parents=True, exist_ok=True) + + # Write the build data to a JSON file so it can be consumed from the + # Sphinx config. + with open(output_path / OUTPUT_PATH_BUILD_META, "w") as f: + json.dump(asdict(build_meta), f) + + # Generate a documentation file for each CLI group. + for group in root_data.groups: + output_path_group = output_path / OUTPUT_PATH_GROUP_FORMAT.format( + name=group.name + ) + output_path_group.parent.mkdir(parents=True, exist_ok=True) + + # Render & write the group documentation + self._template_env.get_template(TEMPLATE_NAME_GROUP).stream( + asdict(group), build_meta=build_meta + ).dump(str(output_path_group)) diff --git a/linodecli/documentation/template_data.py b/linodecli/documentation/template_data.py new file mode 100644 index 000000000..4c62a7c98 --- /dev/null +++ b/linodecli/documentation/template_data.py @@ -0,0 +1,256 @@ +from dataclasses import dataclass, field +from io import StringIO +from typing import Dict, List, Optional, Self + +from linodecli import CLI +from linodecli.baked import OpenAPIOperation +from linodecli.baked.operation import OpenAPIOperationParameter +from linodecli.baked.request import OpenAPIRequestArg +from linodecli.baked.response import OpenAPIResponseAttr +from linodecli.documentation.util import ( + _format_usage_text, + _markdown_to_rst, + _normalize_padding, +) +from linodecli.helpers import sorted_actions_smart + +# Manual corrections to the generated "pretty" names for command groups. +GROUP_NAME_CORRECTIONS = { + "lke": "LKE", + "nodebalancers": "NodeBalancer", + "sshkeys": "SSH Keys", + "vlans": "VLANs", + "vpcs": "VPCs", +} + + +@dataclass +class FilterableAttribute: + """ + Represents a single filterable attribute for a list command/action. + """ + + name: str + type: str + + description: Optional[str] + + @classmethod + def from_openapi(cls, attr: OpenAPIResponseAttr) -> Self: + return cls( + name=attr.name, + type=( + attr.datatype + if attr.item_type is None + else f"{attr.datatype}[{attr.item_type}]" + ), + description=( + _markdown_to_rst(attr.description) + if attr.description != "" + else None + ), + ) + + +@dataclass +class Argument: + """ + Represents a single argument for a command/action. + """ + + path: str + required: bool + type: str + + is_json: bool = False + is_nullable: bool = False + is_parent: bool = False + depth: int = 0 + description: Optional[str] = None + + @classmethod + def from_openapi(cls, arg: OpenAPIRequestArg) -> Self: + return cls( + path=arg.path, + required=arg.required, + type=( + arg.datatype + if arg.item_type is None + else f"{arg.datatype}[{arg.item_type}]" + ), + is_json=arg.format == "json", + is_nullable=arg.nullable, + is_parent=arg.is_parent, + depth=arg.depth, + description=( + _markdown_to_rst(arg.description) + if arg.description != "" + else None + ), + ) + + +@dataclass +class Param: + """ + Represents a single URL parameter for a command/action. + """ + + name: str + type: str + + description: Optional[str] = None + + @classmethod + def from_openapi(cls, param: OpenAPIOperationParameter) -> Self: + return cls( + name=param.name, + type=param.type, + description=( + _markdown_to_rst(param.description) + if param.description is not None + else None + ), + ) + + +@dataclass +class Action: + """ + Represents a single generated Linode CLI command/action. + """ + + command: str + action: List[str] + + usage: Optional[str] = None + summary: Optional[str] = None + description: Optional[str] = None + api_documentation_url: Optional[str] = None + deprecated: bool = False + parameters: List[Param] = field(default_factory=lambda: []) + samples: List[str] = field(default_factory=lambda: []) + filterable_attrs: List[FilterableAttribute] = field( + default_factory=lambda: [] + ) + arguments: List[Argument] = field(default_factory=lambda: []) + + @classmethod + def from_openapi(cls, operation: OpenAPIOperation) -> Self: + result = cls( + command=operation.command, + action=( + operation.action + if isinstance(operation.action, list) + else [operation.action] + ), + summary=_markdown_to_rst(operation.summary), + description=( + _markdown_to_rst(operation.description) + if operation.description != "" + else None + ), + api_documentation_url=operation.docs_url, + deprecated=operation.deprecated, + ) + + if operation.samples: + result.samples = [ + _normalize_padding(sample["source"]) + for sample in operation.samples + ] + + if operation.params: + result.parameters = [ + Param.from_openapi(param) for param in operation.params + ] + + if operation.args: + result.arguments = sorted( + [ + Argument.from_openapi(arg) + for arg in operation.args + if isinstance(arg, OpenAPIRequestArg) + ], + key=lambda arg: (not arg.required, arg.path), + ) + + if operation.method == "get" and operation.response_model.is_paginated: + result.filterable_attrs = sorted( + [ + FilterableAttribute.from_openapi(attr) + for attr in operation.response_model.attrs + if attr.filterable + ], + key=lambda v: v.name, + ) + + result.usage = Action._get_usage(operation) + + return result + + @staticmethod + def _get_usage(operation: OpenAPIOperation) -> str: + usage_io = StringIO() + operation._build_parser()[0].print_usage(file=usage_io) + + return _format_usage_text(usage_io.getvalue()) + + +@dataclass +class Group: + """ + Represents a single "group" of commands/actions as defined by the Linode API. + """ + + name: str + pretty_name: str + actions: List[Action] + + @classmethod + def from_openapi( + cls, name: str, group: Dict[str, OpenAPIOperation] + ) -> Self: + return cls( + name=name, + pretty_name=( + GROUP_NAME_CORRECTIONS[name] + if name in GROUP_NAME_CORRECTIONS + else name.title().replace("-", " ") + ), + actions=sorted_actions_smart( + [Action.from_openapi(action) for action in group.values()], + key=lambda v: v.action[0], + ), + ) + + +@dataclass +class Root: + """ + The root template data structure for the Linode CLI. + """ + + groups: List[Group] + + @classmethod + def from_cli(cls, cli: CLI) -> Self: + return cls( + groups=sorted( + [ + Group.from_openapi(key, group) + for key, group in cli.ops.items() + ], + key=lambda v: v.name, + ), + ) + + +@dataclass +class BuildMeta: + """ + Contains metadata about a single documentation build. + """ + + cli_version: str + api_spec_version: str diff --git a/linodecli/documentation/templates/group.rst.j2 b/linodecli/documentation/templates/group.rst.j2 new file mode 100644 index 000000000..2f6fc0e4a --- /dev/null +++ b/linodecli/documentation/templates/group.rst.j2 @@ -0,0 +1,139 @@ +.. role:: action-subheading +.. role:: action-subheading-description +.. role:: action-argument-required + +{% macro action_details(action) %} +{% set action_title = action.action[0] %} +{% set action_title_format = "`%s <%s>`_" % (action_title, action.api_documentation_url) if action.api_documentation_url else action_title %} +.. _{{ action.command }}_{{ action.action[0] }}: + +{{ action_title_format }} +{{ "-" * (action_title_format | length) }} +{% if action.action | length > 1 %} + +*Aliases: {{ action[1:] | join(", ") }}* +{% endif %} + +{% if action.deprecated %} +.. warning:: + This command is deprecated and may not be supported in the future. +{% endif %} + +{{ action.description }} +{% if action.usage %} + +.. cssclass:: action-subheading + + .. rubric:: Usage + +:action-subheading-description:`The format accepted by this command.` + +.. code-block:: bash + +{{ action.usage | indent(first=True) }} + +{% endif %} +{% if action.samples | length > 0 %} + +.. cssclass:: action-subheading + + .. rubric:: Sample{% if action.samples | length > 1 %}s{% endif %} + + +:action-subheading-description:`Examples of how this command might be used.` + +{% for sample in action.samples %} + +.. code-block:: bash + +{{ sample | indent(first=True) }} + +{% endfor %} +{% endif %} +{% if action.parameters | length > 0 %} + +.. cssclass:: action-subheading + + .. rubric:: Parameters + +:action-subheading-description:`Positional parameters used to define the resource this command should target.` + +.. list-table:: + :header-rows: 1 + :width: 100% + :widths: 15 10 75 + + * - Name + - Type + - Description + +{% for parameter in action.parameters %} + * - :code:`{{ parameter.name }}` + - {{ parameter.type }} + - {% if parameter.description %}{{ parameter.description }}{% else %}N/A{% endif %} + +{% endfor %} +{% endif %} +{% if action.arguments | length > 0 %} + +.. cssclass:: action-subheading + + .. rubric:: Arguments + +:action-subheading-description:`Additional fields used to execute this request.` + +.. list-table:: + :header-rows: 1 + :width: 100% + :widths: 15 10 10 65 + + * - Name + - Required + - Type + - Description + +{% for argument in action.arguments %} + * - :code:`--{{ argument.path }}` + - {% if argument.required %}:action-argument-required:`Yes`{% else %}No{% endif %} + + - {{ argument.type }} + - {% if argument.description %}{{ argument.description }}{% else %}N/A{% endif %} + +{% endfor %} +{% endif %} +{% if action.filterable_attrs | length > 0 %} + +.. rubric:: Filterable Attributes + +`Arguments used to define a filter for response entries.` + +.. list-table:: + :header-rows: 1 + :width: 100% + :widths: 15 10 75 + + * - Name + - Type + - Description + +{% for attr in action.filterable_attrs %} + * - :code:`--{{ attr.name }}` + - *{{ attr.type }}* + - {% if attr.description %}{{ attr.description }}{% else %}N/A{% endif %} + +{% endfor %} +{% endif %} +{% endmacro %} +{{ pretty_name }} +{{ "=" * (pretty_name | length) }} + +This section details {{ pretty_name[:-1] if pretty_name[-1] == "s" else pretty_name }}-related Linode CLI commands. + +{% for action in actions %} +{{ action_details(action) }} + +{% if loop.index < (actions | length) - 1 %} +------------ +{% endif %} + +{% endfor %} \ No newline at end of file diff --git a/linodecli/documentation/util.py b/linodecli/documentation/util.py new file mode 100644 index 000000000..a256cdf49 --- /dev/null +++ b/linodecli/documentation/util.py @@ -0,0 +1,110 @@ +import math +import re + +from linodecli.baked.parsing import REGEX_MARKDOWN_LINK + +REGEX_MARKDOWN_CODE_TAG = re.compile(r"`(?P[^`\s]+)`") +REGEX_USAGE_TOKEN = re.compile(r"(\[[^\[\]]+]|\S+)") +REGEX_PADDING_CHARACTER = re.compile(r"(^ +)", flags=re.M) + + +def _normalize_padding(text: str, pad: str = "\t") -> str: + """ + Normalizes the padding for the given text using the given pad character. + + :param text: The text to normalize. + :param pad: The string to pad with. + + :returns: The normalized text. + """ + + text = text.replace("\t", "") + + padding_lengths = [ + len(match[0]) for match in REGEX_PADDING_CHARACTER.finditer(text) + ] + if len(padding_lengths) < 1: + return text + + spaces_per_tab = min(padding_lengths) + + def _sub_handler(match: re.Match) -> str: + match_length = len(match[0]) + + return pad * math.floor(match_length / spaces_per_tab) + " " * ( + match_length % spaces_per_tab + ) + + return REGEX_PADDING_CHARACTER.sub(_sub_handler, text) + + +def _format_usage_text(text: str, max_length: int = 60, pad: str = "\t") -> str: + """ + Formats the given usage text for use in the output documentation. + + :param text: The usage text to format. + :param max_length: The maximum length of a line in the formatted output. + :param pad: The string to pad lines with. + + :returns: The formatted usage text. + """ + + # Remove the prefix if it exists + if text.startswith("usage: "): + text = text[7:] + + # Apply text wrapping + result = [] + current_line = [] + current_line_length = 0 + + for token in REGEX_USAGE_TOKEN.finditer(text): + token_len = len(token[0]) + + # We've exceeded the maximum length, start a new line + if current_line_length + len(token[0]) > max_length: + result.append(current_line) + current_line = [] + current_line_length = 0 + + current_line.append(token[0]) + current_line_length += token_len + + # If the line has not already been appended, add it now + if len(current_line) > 0: + result.append(current_line) + + return "\n".join( + [ + (pad * (1 if line > 0 else 0)) + " ".join(entries) + for line, entries in enumerate(result) + ] + ) + + +def __markdown_to_rst_sub_handler(match: re.Match) -> str: + link = match["link"] + if link.startswith("/"): + link = f"https://linode.com{link}" + + return f"`{match['text']} <{link}>`_" + + +# TODO: Unify this with the markdown logic under a new `parsing` package. +def _markdown_to_rst(markdown_text: str) -> str: + """ + Translates the given Markdown text into its RST equivalent. + + :param markdown_text: The Markdown text to translate. + + :returns: The translated text. + """ + result = REGEX_MARKDOWN_LINK.sub( + __markdown_to_rst_sub_handler, markdown_text + ) + + result = REGEX_MARKDOWN_CODE_TAG.sub( + lambda match: f":code:`{match['text']}`", result + ) + + return result diff --git a/linodecli/helpers.py b/linodecli/helpers.py index f94096194..24de3c027 100644 --- a/linodecli/helpers.py +++ b/linodecli/helpers.py @@ -6,7 +6,7 @@ import os from argparse import ArgumentParser from pathlib import Path -from typing import Optional +from typing import Callable, List, Optional, TypeVar from urllib.parse import urlparse API_HOST_OVERRIDE = os.getenv("LINODE_CLI_API_HOST") @@ -120,3 +120,36 @@ def expand_globs(pattern: str): print(f"No file found matching pattern {pattern}") return [Path(x).resolve() for x in results] + + +T = TypeVar("T") + + +def sorted_actions_smart( + actions: List[T], key: Callable[[T], str] = lambda v: v +) -> List[T]: + """ + Returns the given list of actions ordered to maximize readability. + + :param actions: The actions to order. + :param key: A function to retrieve the name of a given action. + + :returns: The ordered actions. + """ + + result = [] + root_actions, other_actions = [], [] + + for action in sorted(actions, key=key): + action_key = key(action) + + if "-" not in action_key: + root_actions.append(action) + continue + + other_actions.append(action) + + result.extend(root_actions) + result.extend(other_actions) + + return result diff --git a/linodecli/plugins/README.md b/linodecli/plugins/README.md deleted file mode 100644 index 9dc12151c..000000000 --- a/linodecli/plugins/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# Plugin support - -The Linode CLI supports embedded plugins, features that are hard-coded (instead -of generated as the rest of the CLI is) but are accessible directly through the -CLI as other features are. All plugins are found in this directory. - -## Creating a Plugin - -To create a plugin, simply drop a new python file into this directory or write a -Python module that presents the interface described below. If the -plugin is a Python module, make sure the `call` method is in the `__init__.py` -file in the root of the module. - -Plugins in this directory are called "Internal Plugins," and must meet the -following conditions: - -* Its name must be unique, both with the other plugins and with all commands - offered through the generated CLI -* Its name must not contain special characters, and should be easily to enter - on the command line -* It must contain a `call(args, context)` function for invocation -* It must support a `--help` command as all other CLI commands do. - -Plugins that are installed separately and registered with the `register-plugin` -command are called "Third Party Plugins," and must meet the following -conditions: - -* Its name must be unique, both with the internal plugins and all CLI operations -* It must contain a `call(args, context)` function for invocation -* It must contain a `PLUGIN_NAME` constant whose value is a string that does not - contain special characters, and should be easy to enter on the command line. -* It should support a `--help` command as all other CLI commands do. - -## The Plugin Interface - -All plugins are either an individual python file or a Python module -that reside in this directory or installed separately. Plugins must have one function, `call`, that -matches the following signature: - -```python -def call(args, context): - """ - This is the function used to invoke the plugin. It will receive the remainder - of sys.argv after the plugin's name, and a context of user defaults and config - settings. - """ -``` - -### The PluginContext - -The `PluginContext` class, passed as `context` to the `call` function, includes -all information the plugin is given during invocation. This includes the following: - -* `token` - The Personal Access Token registered with the CLI to make requests -* `client` - The CLI Client object that can make authenticated requests on behalf - of the acting user. This is preferrable to using `requests` or another library - directly (see below). - -#### CLI Client - -The CLI Client provided as `context.client` can make authenticated API calls on -behalf of the user using the provided `call_operation` method. This method is -invoked with a command and an action, and executes the given CLI command as if -it were entered into the command line, returning the resulting status code and -JSON data. - -## Configuration - -Plugins can access the CLI's configuration through the CLI Client mentioned above. -Plugins are allowed to: - -* Read values from the current user's config -* Read and write their own values to the current user's config - -Any other operation is not supported and may break without notice. - -### Methods - -The `Configuration` class provides the following methods for plugins to use: - -**get_value(key)** Returns the value the current user has set for this key, or `None` -if the key does not exist. Currently supported keys are `region`, `type`, and `image`. - -**plugin_set_value(key, value)** Sets a value in the user's config for this plugin. -Plugins can safely set values for any key, and they are namespaced away from other -config keys. - -**plugin_get_value(key)** Returns the value this plugin previously set for the given -key, or `None` if not set. Plugins should assume they are not configured if they -receive `None` when getting a value with this method. - -**write_config()** Writes config changes to disk. This is required to save changes -after calling `plugin_set_value` above. - -### Sample Code - -The following code manipulates and reads from the config in a plugin: - -```python - -def call(args, context): - # get a value from the user's config - default_region = context.client.config.get_value('region') - - # check if we set a value previously - our_value = context.client.config.plugin_get_value('configured') - - if our_value is None: - # plugin not configured - do configuration here - context.client.config.plugin_set_value('configured', 'yes') - - # save the config so changes take effect - context.client.config.write_config() - - # normal plugin code -``` - -## Development - -To develop a plugin, simply create a python source file in this directory that -has a `call` function as described above. To test, simply build the CLI as -normal (via `make install`) or simply by running `./setup.py install` in the -root directory of the project (this installs the code without generating new -baked data, and will only work if you've installed the CLI via `make install` -at least once, however it's a lot faster). - -To develop a third party plugin, simply create and install your module and register -it to the CLI. As long as the `PLUGIN_NAME` doesn't change, updated installations -should invoke the new code. - -### Examples - -This directory contains two example plugins, `echo.py.example` and -`regionstats.py.example`. To run these, simply remove the `.example` at the end -of the file and build the CLI as described above. - -[This directory](https://github.com/linode/linode-cli/tree/main/examples/third-party-plugin) -contains an example Third Party Plugin module. This module is installable and -can be registered to the CLI. diff --git a/pyproject.toml b/pyproject.toml index 8cba2146a..f6da2f2e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,9 @@ dev = [ "requests-mock==1.12.1", "boto3-stubs[s3]", "build>=0.10.0", - "twine>=4.0.2" + "twine>=4.0.2", + "jinja2", + "sphinx_rtd_theme" ] [project.scripts] @@ -41,12 +43,18 @@ linode-cli = "linodecli:main" linode = "linodecli:main" lin = "linodecli:main" +[tool.setuptools] +include-package-data = true + [tool.setuptools.dynamic] version = { attr = "linodecli.version.__version__" } [tool.setuptools.packages.find] include = ["linodecli*"] +[tool.setuptools.package-data] +"linodecli.documentation.templates" = ["*"] + [tool.isort] profile = "black" line_length = 80 diff --git a/wiki/Home.md b/wiki/Home.md deleted file mode 100644 index eb36dd623..000000000 --- a/wiki/Home.md +++ /dev/null @@ -1,4 +0,0 @@ -Welcome to the linode-cli wiki! - -For installation instructions and usage guides, please -refer to the sidebar of this page. \ No newline at end of file diff --git a/wiki/Installation.md b/wiki/Installation.md deleted file mode 100644 index 79db6635a..000000000 --- a/wiki/Installation.md +++ /dev/null @@ -1,69 +0,0 @@ -# Installation - -## PyPi - -```bash -pip3 install linode-cli -# for upgrading -pip3 install linode-cli --upgrade -``` - -## Docker - -### Token -```bash -docker run --rm -it -e LINODE_CLI_TOKEN=$LINODE_TOKEN linode/cli:latest linodes list -``` - -### Config -```bash -docker run --rm -it -v $HOME/.config/linode-cli:/home/cli/.config/linode-cli linode/cli:latest linodes list -``` - -## GitHub Actions - -[Setup Linode CLI](https://github.com/marketplace/actions/setup-linode-cli) GitHub Action to automatically install and authenticate the cli in a GitHub Actions environment: -```yml -- name: Install the Linode CLI - uses: linode/action-linode-cli@v1 - with: - token: ${{ secrets.LINODE_TOKEN }} -``` - -## Community Distributions - -The Linode CLI is available through unofficial channels thanks to our awesome community! These distributions are not included in release testing. - -### Homebrew - -```bash -brew install linode-cli -brew upgrade linode-cli -``` -# Building from Source - -In order to successfully build the CLI, your system will require the following: - -- The `make` command -- `python3` -- `pip3` (to install project dependencies) - -Before attempting a build, install python dependencies like this:: -```bash -make requirements -``` - -Once everything is set up, you can initiate a build like so:: -```bash -make build -``` - -If desired, you may pass in `SPEC=/path/to/openapi-spec` when running `build` -or `install`. This can be a URL or a path to a local spec, and that spec will -be used when generating the CLI. A yaml or json file is accepted. - -To install the package as part of the build process, use this command:: - -```bash -make install -``` diff --git a/wiki/Usage.md b/wiki/Usage.md deleted file mode 100644 index acbbbd4ad..000000000 --- a/wiki/Usage.md +++ /dev/null @@ -1,180 +0,0 @@ -# Usage - -The Linode CLI is invoked with the `linode-cli`. There are two aliases available: `linode` and `lin`. -The CLI accepts two primary arguments, *command* and *action*:: -```bash -linode-cli -``` - -*command* is the part of the CLI you are interacting with, for example "linodes". -You can see a list of all available commands by using `--help`:: -```bash -linode-cli --help -``` - -*action* is the action you want to perform on a given command, for example "list". -You can see a list of all available actions for a command with the `--help` for -that command:: -```bash -linode-cli linodes --help -``` - -Some actions don't require any parameters, but many do. To see details on how -to invoke a specific action, use `--help` for that action:: -```bash -linode-cli linodes create --help -``` - -The first time you invoke the CLI, you will be asked to configure (see -"Configuration" below for details), and optionally select some default values -for "region," "image," and "type." If you configure these defaults, you may -omit them as parameters to actions and the default value will be used. - -## Common Operations - -List Linodes:: -```bash -linode-cli linodes list -``` - -List Linodes in a Region:: -```bash -linode-cli linodes list --region us-east -``` - -Make a Linode:: -```bash -linode-cli linodes create --type g5-standard-2 --region us-east --image linode/debian9 --label cli-1 --root_pass -``` - -Make a Linode using Default Settings:: -```bash -linode-cli linodes create --label cli-2 --root_pass -``` - -Reboot a Linode:: -```bash -linode-cli linodes reboot 12345 -``` - -View available Linode types:: -```bash -linode-cli linodes types -``` - -View your Volumes:: -```bash -linode-cli volumes list -``` - -View your Domains:: -```bash -linode-cli domains list -``` - -View records for a single Domain:: -```bash -linode-cli domains records-list 12345 -``` - -View your user:: -```bash -linode-cli profile view -``` - -## Specifying List Arguments - -When running certain commands, you may need to specify multiple values for a list -argument. This can be done by specifying the argument multiple times for each -value in the list. For example, to create a Linode with multiple `tags` -you can execute the following:: -```bash -linode-cli linodes create --region us-east --type g6-nanode-1 --tags tag1 --tags tag2 -``` - -Lists consisting of nested structures can also be expressed through the command line. -Duplicated attribute will signal a different object. -For example, to create a Linode with a public interface on `eth0` and a VLAN interface -on `eth1` you can execute the following:: -```bash -linode-cli linodes create \ - --region us-east --type g6-nanode-1 --image linode/ubuntu22.04 \ - --root_pass "myr00tp4ss123" \ - # The first interface (index 0) is defined with the public purpose - --interfaces.purpose public \ - # The second interface (index 1) is defined with the vlan purpose. - # The duplicate `interfaces.purpose` here tells the CLI to start building a new interface object. - --interfaces.purpose vlan --interfaces.label my-vlan -``` - -## Specifying Nested Arguments - -When running certain commands, you may need to specify an argument that is nested -in another field. These arguments can be specified using a `.` delimited path to -the argument. For example, to create a firewall with an inbound policy of `DROP` -and an outbound policy of `ACCEPT`, you can execute the following: -```bash -linode-cli firewalls create --label example-firewall --rules.outbound_policy ACCEPT --rules.inbound_policy DROP -``` - -## Special Arguments - -In some cases, certain values for arguments may have unique functionality. - -### Null Values - -Arguments marked as nullable can be passed the value `null` to send an explicit null value to the Linode API: - -```bash -linode-cli networking ip-update --rdns null 127.0.0.1 -``` - -### Empty Lists - -List arguments can be passed the value `[]` to send an explicit empty list value to the Linode API: - -```bash -linode-cli networking ip-share --linode_id 12345 --ips [] -``` - -## Suppressing Defaults - -If you configured default values for `image`, `authorized_users`, `region`, -database `engine`, and Linode `type`, they will be sent for all requests that accept them -if you do not specify a different value. If you want to send a request *without* these -arguments, you must invoke the CLI with the `--no-defaults` option. - -For example, to create a Linode with no `image` after a default Image has been -configured, you would do this:: -```bash -linode-cli linodes create --region us-east --type g5-standard-2 --no-defaults -``` - -## Suppressing Warnings - -In some situations, like when the CLI is out of date, it will generate a warning -in addition to its normal output. If these warnings can interfere with your -scripts or you otherwise want them disabled, simply add the `--suppress-warnings` -flag to prevent them from being emitted. - -## Suppressing Retries - -Sometimes the API responds with a error that can be ignored. For example a timeout -or nginx response that can't be parsed correctly, by default the CLI will retry -calls on these errors we've identified. If you'd like to disable this behavior for -any reason use the ``--no-retry`` flag. - -## Shell Completion - -To generate a completion file for a given shell type, use the `completion` command; -for example to generate completions for bash run:: -```bash -linode-cli completion bash -``` - -The output of this command is suitable to be included in the relevant completion -files to enable command completion on your shell. - -This command currently supports completions bash and fish shells. - -Use `bashcompinit` on zsh with the bash completions for support on zsh shells. diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md deleted file mode 100644 index a22828883..000000000 --- a/wiki/_Sidebar.md +++ /dev/null @@ -1,10 +0,0 @@ -- [Installation](./Installation) -- [Configuration](./Configuration) -- [Usage](./Usage) -- [Output](./Output) -- [Plugins](./Plugins) -- [Development](./Development%20-%20Index) - - [Overview](./Development%20-%20Overview) - - [Skeleton](./Development%20-%20Skeleton) - - [Setup](./Development%20-%20Setup) - - [Testing](./Development%20-%20Testing) \ No newline at end of file diff --git a/wiki/development/Development - Index.md b/wiki/development/Development - Index.md deleted file mode 100644 index 291141a1d..000000000 --- a/wiki/development/Development - Index.md +++ /dev/null @@ -1,12 +0,0 @@ -This guide will help you get started developing against and contributing to the Linode CLI. - -## Index - -1. [Overview](./Development%20-%20Overview) -2. [Skeleton](./Development%20-%20Skeleton) -3. [Setup](./Development%20-%20Setup) -4. [Testing](./Development%20-%20Testing) - -## Contributing - -Once you're ready to contribute a change to the project, please refer to our [Contributing Guide](https://github.com/linode/linode-cli/blob/dev/CONTRIBUTING.md). \ No newline at end of file diff --git a/wiki/development/Development - Overview.md b/wiki/development/Development - Overview.md deleted file mode 100644 index 78cc95d47..000000000 --- a/wiki/development/Development - Overview.md +++ /dev/null @@ -1,104 +0,0 @@ -The following section outlines the core functions of the Linode CLI. - -## OpenAPI Specification Parsing - -Most Linode CLI commands (excluding [plugin commands](https://github.com/linode/linode-cli/tree/dev/linodecli/plugins)) -are generated dynamically at build-time from the [Linode OpenAPI Specification](https://github.com/linode/linode-api-docs), -which is also used to generate the [official Linode API documentation](https://www.linode.com/docs/api/). - -Each OpenAPI spec endpoint method is parsed into an `OpenAPIOperation` object. -This object includes all necessary request and response arguments to create a command, -stored as `OpenAPIRequestArg` and `OpenAPIResponseAttr` objects respectively. -At runtime, the Linode CLI changes each `OpenAPIRequestArg` to an argparse argument and -each `OpenAPIResponseAttr` to an outputtable column. It can also manage complex structures like -nested objects and lists, resulting in commands and outputs that may not -exactly match the OpenAPI specification. - -## OpenAPI Specification Extensions - -In order to better support the Linode CLI, the following [Specification Extensions](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.1.md#specificationExtensions) have been added to Linode's OpenAPI spec: - -| Attribute | Location | Purpose | -| --- | --- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| x-linode-cli-action | method | The action name for operations under this path. If not present, operationId is used. | -| x-linode-cli-color | property | If present, defines key-value pairs of property value: color. Colors must be one of the [standard colors](https://rich.readthedocs.io/en/stable/appendix/colors.html#appendix-colors) that accepted by Rich. Must include a default. | -| x-linode-cli-command | path | The command name for operations under this path. If not present, "default" is used. | -| x-linode-cli-display | property | If truthy, displays this as a column in output. If a number, determines the ordering (left to right). | -| x-linode-cli-format | property | Overrides the "format" given in this property for the CLI only. Valid values are `file` and `json`. | -| x-linode-cli-skip | path | If present and truthy, this method will not be available in the CLI. | -| x-linode-cli-allowed-defaults| requestBody | Tells the CLI what configured defaults apply to this request. Valid defaults are "region", "image", "authorized_users", "engine", and "type". | -| x-linode-cli-nested-list | content-type| Tells the CLI to flatten a single object into multiple table rows based on the keys included in this value. Values should be comma-delimited JSON paths, and must all be present on response objects. When used, a new key `_split` is added to each flattened object whose value is the last segment of the JSON path used to generate the flattened object from the source. | -| x-linode-cli-use-schema | content-type| Overrides the normal schema for the object and uses this instead. Especially useful when paired with ``x-linode-cli-nested-list``, allowing a schema to describe the flattened object instead of the original object. | -| x-linode-cli-subtables | content-type| Indicates that certain response attributes should be printed in a separate "sub"-table. This allows certain endpoints with nested structures in the response to be displayed correctly. | - -## Baking - -The "baking" process is run with `make bake`, `make install`, and `make build` targets, -wrapping the `linode-cli bake` command. - -Objects representing each command are serialized into the `data-3` file via the [pickle](https://docs.python.org/3/library/pickle.html) -package, and are included in release artifacts as a [data file](https://setuptools.pypa.io/en/latest/userguide/datafiles.html). -This enables quick command loading at runtime and eliminates the need for runtime parsing logic. - -## Configuration - -The Linode CLI can be configured using the `linode-cli configure` command, which allows users to -configure the following: - -- A Linode API token - - This can optionally be done using OAuth, see [OAuth Authentication](#oauth-authentication) -- Default values for commonly used fields (e.g. region, image) -- Overrides for the target API URL (hostname, version, scheme, etc.) - -This command serves as an interactive prompt and outputs a configuration file to `~/.config/linode-cli`. -This file is in a simple INI format and can be easily modified manually by users. - -Additionally, multiple users can be created for the CLI which can be designated when running commands using the `--as-user` argument -or using the `default-user` config variable. - -When running a command, the config file is loaded into a `CLIConfig` object stored under the `CLI.config` field. -This object allows various parts of the CLI to access the current user, the configured token, and any other CLI config values by name. - -The logic for the interactive prompt and the logic for storing the CLI configuration can be found in the -`configuration` package. - -## OAuth Authentication - -In addition to allowing users to configure a token manually, they can automatically generate a CLI token under their account using -an OAuth workflow. This workflow uses the [Linode OAuth API](https://www.linode.com/docs/api/#oauth) to generate a temporary token, -which is then used to generate a long-term token stored in the CLI config file. - -The OAuth client ID is hardcoded and references a client under an officially managed Linode account. - -The rough steps of this OAuth workflow are as follows: - -1. The CLI checks whether a browser can be opened. If not, manually prompt the user for a token and skip. -2. Open a local HTTP server on an arbitrary port that exposes `oauth-landing-page.html`. This will also extract the token from the callback. -3. Open the user's browser to the OAuth URL with the hardcoded client ID and the callback URL pointing to the local webserver. -4. Once the user authorizes the OAuth application, they will be redirected to the local webserver where the temporary token will be extracted. -5. With the extracted token, a new token is generated with the default callback and a name similar to `Linode CLI @ localhost`. - -All the logic for OAuth token generation is stored in the `configuration/auth.py` file. - -## Outputs - -The Linode CLI uses the [Rich Python package](https://rich.readthedocs.io/en/latest/) to render tables, colorize text, -and handle other complex terminal output operations. - -## Output Overrides - -For special cases where the desired output may not be possible using OpenAPI spec extensions alone, developers -can implement special override functions that are given the output JSON and print a custom output to stdout. - -These overrides are specified using the `@output_override` decorator and can be found in the `overrides.py` file. - -## Command Completions - -The Linode CLI allows users to dynamically generate shell completions for the Bash and Fish shells. -This works by rendering hardcoded templates for each baked/generated command. - -See `completion.py` for more details. - -## Next Steps - -To continue to the next step of this guide, continue to the [Skeleton page](./Development%20-%20Skeleton). diff --git a/wiki/development/Development - Setup.md b/wiki/development/Development - Setup.md deleted file mode 100644 index bf667fcbe..000000000 --- a/wiki/development/Development - Setup.md +++ /dev/null @@ -1,86 +0,0 @@ -The following guide outlines to the process for setting up the Linode CLI for development. - -## Cloning the Repository - -The Linode CLI repository can be cloned locally using the following command: - -```bash -git clone git@github.com:linode/linode-cli.git -``` - -If you do not have an SSH key configured, you can alternatively use the following command: - -```bash -git clone https://github.com/linode/linode-cli.git -``` - -## Configuring a VirtualEnv (recommended) - -A virtual env allows you to create virtual Python environment which can prevent potential -Python dependency conflicts. - -To create a VirtualEnv, run the following: - -```bash -python3 -m venv .venv -``` - -To enter the VirtualEnv, run the following command (NOTE: This needs to be run every time you open your shell): - -```bash -source .venv/bin/activate -``` - -## Installing Project Dependencies - -All Linode CLI Python requirements can be installed by running the following command: - -```bash -make requirements -``` - -## Building and Installing the Project - -The Linode CLI can be built and installed using the `make install` target: - -```bash -make install -``` - -Alternatively you can build but not install the CLI using the `make build` target: - -```bash -make build -``` - -Optionally you can validate that you have installed a local version of the CLI using the `linode-cli --version` command: - -```bash -linode-cli --version - -# Output: -# linode-cli 0.0.0 -# Built from spec version 4.173.0 -# -# The 0.0.0 implies this is a locally built version of the CLI -``` - -## Building Using a Custom OpenAPI Specification - -In some cases, you may want to build the CLI using a custom or modified OpenAPI specification. - -This can be achieved using the `SPEC` Makefile argument, for example: - -```bash -# Download the OpenAPI spec -curl -o openapi.yaml https://raw.githubusercontent.com/linode/linode-api-docs/development/openapi.yaml - -# Many arbitrary changes to the spec - -# Build & install the CLI using the modified spec -make SPEC=$PWD/openapi.yaml install -``` - -## Next Steps - -To continue to the next step of this guide, continue to the [Testing page](./Development%20-%20Testing). \ No newline at end of file diff --git a/wiki/development/Development - Skeleton.md b/wiki/development/Development - Skeleton.md deleted file mode 100644 index ff9633d77..000000000 --- a/wiki/development/Development - Skeleton.md +++ /dev/null @@ -1,32 +0,0 @@ -The following section outlines the purpose of each file in the CLI. - -* `linode-cli` - * `baked` - * `__init__.py` - Contains imports for certain classes in this package - * `colors.py` - Contains logic for colorizing strings in CLI outputs (deprecated) - * `operation.py` - Contains the logic to parse an `OpenAPIOperation` from the OpenAPI spec and generate/execute a corresponding argparse parser - * `request.py` - Contains the `OpenAPIRequest` and `OpenAPIRequestArg` classes - * `response.py` - Contains `OpenAPIResponse` and `OpenAPIResponseAttr` classes - * `configuration` - * `__init__.py` - Contains imports for certain classes in this package - * `auth.py` - Contains all the logic for the token generation OAuth workflow - * `config.py` - Contains all the logic for loading, updating, and saving CLI configs - * `helpers.py` - Contains various config-related helpers - * `plugins` - * `__init__.py` - Contains imports for certain classes in this package - * `plugins.py` - Contains the shared wrapper that allows plugins to access CLI functionality - * `__init__.py` - Contains the main entrypoint for the CLI; routes top-level commands to their corresponding functions - * `__main__.py` - Calls the project entrypoint in `__init__.py` - * `api_request.py` - Contains logic for building API request bodies, making API requests, and handling API responses/errors - * `arg_helpers.py` - Contains miscellaneous logic for registering common argparse arguments and loading the OpenAPI spec - * `cli.py` - Contains the `CLI` class, which routes all the logic baking, loading, executing, and outputting generated CLI commands - * `completion.py` - Contains all the logic for generating shell completion files (`linode-cli completion`) - * `helpers.py` - Contains various miscellaneous helpers, especially relating to string manipulation, etc. - * `oauth-landing-page.html` - The page to show users in their browser when the OAuth workflow is complete. - * `output.py` - Contains all the logic for handling generated command outputs, including formatting tables, filtering JSON, etc. - * `overrides.py` - Contains hardcoded output override functions for select CLI commands. - - -## Next Steps - -To continue to the next step of this guide, continue to the [Setup page](./Development%20-%20Setup). \ No newline at end of file diff --git a/wiki/development/Development - Testing.md b/wiki/development/Development - Testing.md deleted file mode 100644 index c97c04b46..000000000 --- a/wiki/development/Development - Testing.md +++ /dev/null @@ -1,31 +0,0 @@ -This page gives an overview of how to run the various test suites for the Linode CLI. - -Before running any tests, built and installed the Linode CLI with your changes using `make install`. - -## Running Unit Tests - -Unit tests can be run using the `make testunit` Makefile target. - -## Running Integration Tests - -Running the tests locally is simple. The only requirements are that you export Linode API token as `LINODE_CLI_TOKEN`:: -```bash -export LINODE_CLI_TOKEN="your_token" -``` - -More information on Managing Linode API tokens can be found in our [API Token Docs](https://www.linode.com/docs/products/tools/api/guides/manage-api-tokens/). - -In order to run the full integration test, run:: -```bash -make testint -``` - -To run specific test package, use environment variable `INTEGRATION_TEST_PATH` with `testint` command:: -```bash -make INTEGRATION_TEST_PATH="cli" testint -``` - -Lastly, to run specific test case, use environment variables `TEST_CASE` with `testint` command:: -```bash -make TEST_CASE=test_help_page_for_non_aliased_actions testint -``` From e01e9619caf8e38b395fb8537ab18fd512afdad6 Mon Sep 17 00:00:00 2001 From: Lena Garber Date: Fri, 30 Aug 2024 13:54:36 -0400 Subject: [PATCH 02/39] Add publish-docs workflow --- .github/workflows/publish-docs.yml | 92 + Makefile | 4 +- openapi.yaml.tmp | 80623 +++++++++++++++++++++++++++ 3 files changed, 80718 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/publish-docs.yml create mode 100644 openapi.yaml.tmp diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml new file mode 100644 index 000000000..9c1934a2e --- /dev/null +++ b/.github/workflows/publish-docs.yml @@ -0,0 +1,92 @@ +name: Build and Publish Documentation + +on: + push: + branches: + - main + - dev + + # TODO: Remove this line + - new/doc-generation + + release: + types: + - published + + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +# Make sure we avoid a race condition =) +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + name: Build the documentation + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: 'recursive' + + - name: Update system packages + run: sudo apt-get update -y + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install Python dependencies and update cert + run: | + pip install wheel boto3 && \ + pip install certifi -U && \ + pip install .[obj,dev] + + - name: Build the documentation + run: make generate-docs + env: + # We need to define a token to prevent the CLI from + # attempting to do a first-time configuration. + LINODE_CLI_TOKEN: foobar + + - name: Upload the artifact + uses: actions/upload-artifact@v4 + with: + name: generated-docs-html + path: docs/build/html + + publish: + name: Publish the documentation + runs-on: ubuntu-latest + needs: + - build + steps: + - name: Download the artifact from the previous job + uses: actions/download-artifact@v4 + with: + name: generated-docs-html + path: .docs-html + + # TODO: Implement some sort of page merging logic here so we can host + # separate pages for `dev`, `main` and commit hashes. + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + with: + enablement: true + + - name: Push the rendered documentation site to GitHub Pages + uses: actions/upload-pages-artifact@v3 + with: + path: .docs-html + + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 diff --git a/Makefile b/Makefile index 662711835..5928bb566 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,8 @@ ifdef TEST_CASE TEST_CASE_COMMAND = -k $(TEST_CASE) endif +# TODO: Revert this once the corrected spec is available. +SPEC := $(PWD)/openapi.yaml.tmp SPEC_VERSION ?= latest ifndef SPEC @@ -91,7 +93,7 @@ clean-docs-commands: rm -rf "$(SPHINX_GENERATED_PATH)" .PHONY: generate-docs -generate-docs-commands: clean-docs-commands +generate-docs-commands: bake clean-docs-commands python3 -m linodecli generate-docs "$(SPHINX_GENERATED_PATH)" .PHONY: generate-docs diff --git a/openapi.yaml.tmp b/openapi.yaml.tmp new file mode 100644 index 000000000..e6d0def61 --- /dev/null +++ b/openapi.yaml.tmp @@ -0,0 +1,80623 @@ +openapi: "3.0.1" +info: + license: + url: "https://www.apache.org/licenses/LICENSE-2.0.html" + name: "Apache 2.0" + description: "[Read the API documentation](https://techdocs.akamai.com/linode-api/reference/api)." + contact: + email: "support@linode.com" + name: "Linode" + url: "https://linode.com" + version: "4.177.1" + title: "Linode API" +servers: + - + url: "https://api.linode.com" +x-readme: + samples-languages: + - "curl" + - "python" + - "node" +x-akamai: + file-path: "01-account.yaml" + auth-type: "OAUTH" +externalDocs: + url: "https://techdocs.akamai.com/linode-api/reference" + description: "See documentation for Akamai's Linode API" +components: + parameters: + id-path: + in: "path" + required: true + x-akamai: + file-path: "parameters/id-path.yaml" + name: "id" + description: "The slug for the applicable data center. Run the [List regions](https://techdocs.akamai.com/linode-api/reference/get-regions) operation to view the slug for each data center." + schema: + type: "string" + payment-id-path: + required: true + schema: + type: "integer" + in: "path" + x-akamai: + file-path: "parameters/payment-id-path.yaml" + name: "paymentId" + description: "The ID of the Payment to look up." + payment-method-id-path-6078bc7b: + required: true + x-akamai: + file-path: "parameters/payment-method-id-path-6078bc7b.yaml" + in: "path" + description: "The ID of the Payment Method to look up." + name: "paymentMethodId" + schema: + type: "integer" + client-id-path: + name: "clientId" + description: "The OAuth Client ID to look up." + in: "path" + x-akamai: + file-path: "parameters/client-id-path.yaml" + required: true + schema: + type: "string" + username-path: + schema: + type: "string" + required: true + x-akamai: + file-path: "parameters/username-path.yaml" + in: "path" + description: "The username to look up." + name: "username" + event-id-path-39255fcf: + schema: + type: "integer" + description: "The ID of the Event." + name: "eventId" + required: true + x-akamai: + file-path: "parameters/event-id-path-39255fcf.yaml" + in: "path" + page-size: + schema: + default: 100 + minimum: 25 + type: "integer" + maximum: 500 + in: "query" + x-akamai: + file-path: "parameters/page-size.yaml" + name: "page_size" + description: "The number of items to return per page." + token-path-faf66b58: + in: "path" + x-akamai: + file-path: "parameters/token-path-faf66b58.yaml" + name: "token" + description: "The UUID of the Entity Transfer." + schema: + format: "uuid" + type: "string" + required: true + event-id-path-214cd042: + x-akamai: + file-path: "parameters/event-id-path-214cd042.yaml" + in: "path" + description: "The ID of the Event to designate as seen." + name: "eventId" + required: true + schema: + type: "integer" + client-id-path-ecf807fb: + x-akamai: + file-path: "parameters/client-id-path-ecf807fb.yaml" + in: "path" + description: "The OAuth Client ID to look up." + name: "clientId" + schema: + type: "string" + required: true + invoice-id-path: + schema: + type: "integer" + in: "path" + required: true + x-akamai: + file-path: "parameters/invoice-id-path.yaml" + name: "invoiceId" + description: "The ID of the Invoice." + api-version-path: + schema: + enum: + - "v4" + - "v4beta" + default: "v4" + type: "string" + in: "path" + x-akamai: + file-path: "parameters/api-version-path.yaml" + required: true + name: "apiVersion" + description: "Call either the `v4` URL, or `v4beta` for operations still in Beta." + payment-method-id-path-fb39a844: + schema: + type: "integer" + name: "paymentMethodId" + description: "The ID of the Payment Method to make default." + in: "path" + required: true + x-akamai: + file-path: "parameters/payment-method-id-path-fb39a844.yaml" + event-id-path-625aa248: + schema: + type: "integer" + in: "path" + required: true + x-akamai: + file-path: "parameters/event-id-path-625aa248.yaml" + name: "eventId" + description: "The ID of the Event to designate as read." + beta-id: + schema: + type: "string" + x-akamai: + file-path: "parameters/beta-id.yaml" + required: true + in: "path" + description: "The ID of the Beta Program." + name: "betaId" + page-offset: + in: "query" + x-akamai: + file-path: "parameters/page-offset.yaml" + required: false + name: "page" + description: "The page of a collection to return." + schema: + default: 1 + type: "integer" + minimum: 1 + token-path-f857f5a2: + schema: + format: "uuid" + type: "string" + name: "token" + description: "The UUID of the Service Transfer." + in: "path" + x-akamai: + file-path: "parameters/token-path-f857f5a2.yaml" + required: true + login-id-path: + in: "path" + x-akamai: + file-path: "parameters/login-id-path.yaml" + name: "loginId" + description: "The ID of the login object to access." + schema: + type: "integer" + required: true + eeuid: + description: "The child account to look up. You can run the [List child accounts](https://techdocs.akamai.com/linode-api/reference/get-child-accounts) operation to find the applicable account and store its `euuid`." + name: "euuid" + required: true + x-akamai: + file-path: "parameters/eeuid.yaml" + in: "path" + schema: + type: "string" + schemas: + started: + format: "date-time" + x-linode-cli-display: 5 + x-akamai: + labels: + - "Filterable" + type: "string" + description: "__Filterable__, __Read-only__ The start date-time of the Beta Program." + readOnly: true + example: "2023-07-11T00:00:00" + x-linode-filterable: true + promotion: + additionalProperties: false + properties: + service_type: + x-linode-cli-display: 1 + type: "string" + description: "The service to which this promotion applies." + example: "all" + enum: + - "all" + - "backup" + - "blockstorage" + - "db_mysql" + - "ip_v4" + - "linode" + - "linode_disk" + - "linode_memory" + - "loadbalancer" + - "longview" + - "managed" + - "nodebalancer" + - "objectstorage" + - "placement_group" + - "transfer_tx" + this_month_credit_remaining: + example: "10.00" + description: "The amount of credit left for this month for this promotion." + type: "string" + x-linode-cli-display: 4 + expire_dt: + description: "When this promotion's credits expire." + type: "string" + x-linode-cli-display: 2 + example: "2018-01-31T23:59:59" + summary: + example: "$10 off your Linode a month!" + type: "string" + description: "Short details of this promotion." + x-linode-cli-display: 10 + description: + description: "A detailed description of this promotion." + type: "string" + example: "Receive up to $10 off your services every month for 6 months! Unused credits will expire once this promotion period ends." + credit_monthly_cap: + description: "The amount available to spend per month." + type: "string" + x-linode-cli-display: 5 + example: "10.00" + credit_remaining: + type: "string" + description: "The total amount of credit left for this promotion." + x-linode-cli-display: 3 + example: "50.00" + image_url: + example: "https://linode.com/10_a_month_promotion.svg" + description: "The location of an image for this promotion." + type: "string" + x-akamai: + file-path: "schemas/promotion.yaml" + description: "__Read-only__ Promotions generally offer a set amount of credit that can be used toward your Linode services, and the promotion expires after a specified date. As well, a monthly cap on the promotional offer is set.\n\nSimply put, a promotion offers a certain amount of credit month, until either the expiration date is passed, or until the total promotional credit is used, whichever comes first." + type: "object" + readOnly: true + added-get-users-200: + type: "object" + properties: + pages: + type: "integer" + description: "__Read-only__ The total number of [pages](https://techdocs.akamai.com/linode-api/reference/pagination)." + readOnly: true + example: 1 + page: + description: "__Read-only__ The current [page](https://techdocs.akamai.com/linode-api/reference/pagination)." + type: "integer" + readOnly: true + example: 1 + data: + type: "array" + items: + allOf: + - + x-akamai: + file-path: "schemas/user.yaml" + properties: + ssh_keys: + items: + type: "string" + type: "array" + description: "__Read-only__ A list of SSH Key labels added by this User.\n\nUsers can add keys with the [Add an SSH key](https://techdocs.akamai.com/linode-api/reference/post-add-ssh-key) operation.\n\nThese keys are deployed when this User is included in the `authorized_users` field of the following requests:\n\n- [Create a Linode](https://techdocs.akamai.com/linode-api/reference/post-linode-instance)\n- [Rebuild a Linode](https://techdocs.akamai.com/linode-api/reference/post-rebuild-linode-instance)\n- [Create a disk](https://techdocs.akamai.com/linode-api/reference/post-add-linode-disk)" + readOnly: true + example: + - "home-pc" + - "laptop" + email: + example: "example_user@linode.com" + x-linode-cli-display: 2 + format: "email" + type: "string" + description: "The email address for the User. Linode sends emails to this address for account management communications. May be used for other communications as configured." + restricted: + x-linode-cli-display: 3 + description: "If true, the User must be granted access to perform actions or access entities on this Account. Run [List a user's grants](https://techdocs.akamai.com/linode-api/reference/get-user-grants) for details on how to configure grants for a restricted User." + type: "boolean" + example: true + password_created: + readOnly: true + example: "2018-01-01T01:01:01" + format: "date-time" + type: "string" + description: "__Read-only__ The date and time when this User's current password was created.\n\nUser passwords are first created during the Account sign-up process, and updated using the [Reset Password](https://login.linode.com/forgot/password) webpage.\n\n`null` if this User has not created a password yet." + nullable: true + tfa_enabled: + type: "boolean" + description: "__Read-only__ A boolean value indicating if the User has Two Factor Authentication (TFA) enabled. Run the [Create a two factor secret](https://techdocs.akamai.com/linode-api/reference/post-tfa-enable) operation to enable TFA." + readOnly: true + example: true + username: + description: "__Filterable__ The User's username. This is used for logging in, and may also be displayed alongside actions the User performs (for example, in Events or public StackScripts)." + type: "string" + x-linode-cli-display: 1 + x-akamai: + labels: + - "Filterable" + minLength: 3 + pattern: "^[a-zA-Z0-9]((?![_-]{2,})[a-zA-Z0-9-_])+[a-zA-Z0-9]$" + maxLength: 32 + example: "example_user" + x-linode-filterable: true + last_login: + readOnly: true + additionalProperties: false + description: "__Read-only__ Information for the most recent login attempt for this User.\n\n`null` if no login attempts have been made since creation of this User.\n\nRun the [List user logins](https://techdocs.akamai.com/linode-api/reference/get-account-logins) operation for additional login information." + type: "object" + nullable: true + properties: + status: + readOnly: true + enum: + - "successful" + - "failed" + example: "successful" + description: "__Read-only__ The result of the most recent login attempt for this User." + type: "string" + login_datetime: + example: "2018-01-01T01:01:01" + readOnly: true + type: "string" + description: "__Read-only__ The date and time of this User's most recent login attempt." + format: "date-time" + verified_phone_number: + readOnly: true + example: "+5555555555" + format: "phone" + type: "string" + description: "__Read-only__ The phone number verified for this User Profile with the [Verify a phone number](https://techdocs.akamai.com/linode-api/reference/post-profile-phone-number-verify) operation.\n\n`null` if this User Profile has no verified phone number." + nullable: true + type: "object" + description: "A User on your Account. Unrestricted users can log in and access information about your Account, while restricted users may only access entities or perform actions they've been granted access to." + additionalProperties: false + - + additionalProperties: false + description: "The type of user on an account. Mostly applies to the use of the parent and child accounts for Akamai partners functionality." + type: "object" + x-akamai: + file-path: "schemas/user-type.yaml" + properties: + user_type: + readOnly: true + example: "parent" + enum: + - "parent" + - "child" + - "proxy" + - "default" + description: "__Read-only__ If the user belongs to a [parent or child account](https://www.linode.com/docs/guides/parent-child-accounts/) relationship, this defines the user type in the respective account. Possible values include:\n\n- `parent`. This is a user in an Akamai partner account. Akamai partners have a contractural relationship with their end customers, to sell Akamai services. This user can either have full access (a parent account admin user) or limited access. Limited users don't have access to manage child accounts, but they can be granted this access by an admin user.\n\n- `child`. This is an Akamai partner's end customer user, in a child account. A child user can have either full or limited access. Full access lets the user manage other child users and the proxy user in a child account.\n\n- `proxy`. This is a user on a child account that gives parent account users access to that child account. A parent account user with the `child_account_access` grant can [Create a proxy user token](https://techdocs.akamai.com/linode-api/reference/post-child-account-token) from the parent account. The parent user can use this token to run API operations from the child account, as if they were a child user.\n\n- `default`. This applies to all regular, non-parent-child account users." + type: "string" + results: + example: 1 + readOnly: true + type: "integer" + description: "__Read-only__ The total number of results." + x-akamai: + file-path: "schemas/added-get-users-200.yaml" + additionalProperties: false + invoice: + description: "Account Invoice object." + type: "object" + properties: + date: + readOnly: true + example: "2018-01-01T00:01:01" + x-linode-filterable: true + x-linode-cli-display: 2 + format: "date-time" + x-akamai: + labels: + - "Filterable" + type: "string" + description: "__Filterable__, __Read-only__ When this Invoice was generated." + id: + description: "__Read-only__ The Invoice's unique ID." + type: "integer" + x-linode-cli-display: 1 + example: 123 + readOnly: true + tax_summary: + description: "__Read-only__ The amount of tax broken down into subtotals by source." + type: "array" + items: + properties: + name: + description: "The source of this tax subtotal." + type: "string" + example: "PA STATE TAX" + tax: + description: "The amount of tax subtotal attributable to this source." + type: "number" + example: 12.25 + type: "object" + additionalProperties: false + readOnly: true + tax: + x-linode-cli-display: 5 + type: "number" + description: "__Read-only__ The amount of tax levied on the Invoice in US Dollars." + readOnly: true + example: 12.25 + billing_source: + x-akamai: + labels: + - "Filterable" + x-linode-cli-display: 3.5 + type: "string" + description: "__Filterable__, __Read-only__ `akamai`: This Invoice was generated according to the terms of an agreement between the customer and Akamai.\n\n`linode`: This Invoice was generated according to the default terms, prices, and discounts." + readOnly: true + x-linode-filterable: true + enum: + - "akamai" + - "linode" + example: "linode" + total: + x-linode-cli-display: 6 + x-akamai: + labels: + - "Filterable" + type: "number" + description: "__Filterable__, __Read-only__ The amount of the Invoice after taxes in US Dollars." + readOnly: true + example: 132.5 + x-linode-filterable: true + label: + example: "Invoice" + x-linode-filterable: true + readOnly: true + type: "string" + description: "__Filterable__, __Read-only__ The Invoice's display label." + x-linode-cli-display: 3 + x-akamai: + labels: + - "Filterable" + subtotal: + readOnly: true + example: 120.25 + x-linode-cli-display: 4 + description: "__Read-only__ The amount of the Invoice before taxes in US Dollars." + type: "number" + x-akamai: + file-path: "schemas/invoice.yaml" + additionalProperties: false + child-account: + additionalProperties: false + x-akamai: + file-path: "schemas/child-account.yaml" + properties: + zip: + x-linode-filterable: true + example: "92111-1234" + x-akamai: + labels: + - "Filterable" + type: "string" + description: "__Filterable__ The zip code of this Account's billing address. The following restrictions apply:\n\n- Can only contain ASCII letters, numbers, and hyphens (`-`).\n- Can't contain more than 9 letter or number characters." + address_2: + type: "string" + description: "__Filterable__ Second line of this child account's billing address, if applicable." + x-akamai: + labels: + - "Filterable" + x-linode-filterable: true + example: "Suite A" + maxLength: 64 + capabilities: + readOnly: true + example: + - "Linodes" + - "NodeBalancers" + - "Block Storage" + - "Object Storage" + items: + type: "string" + type: "array" + description: "__Read-only__ A list of the capabilities the child account supports." + first_name: + example: "John" + maxLength: 50 + x-linode-filterable: true + type: "string" + description: "__Filterable__ The first name of the owner of this child account. It can't include any of these characters: `<` `>` `(` `)` `\"` `=`." + x-linode-cli-display: 1 + x-akamai: + labels: + - "Filterable" + active_since: + readOnly: true + example: "2018-01-01T00:01:01" + format: "date-time" + description: "__Read-only__ The activation date and time for the child account." + type: "string" + balance: + description: "__Read-only__ This child account's balance, in US dollars." + type: "number" + x-linode-cli-display: 4 + example: 200 + readOnly: true + city: + example: "San Diego" + maxLength: 24 + x-linode-filterable: true + x-akamai: + labels: + - "Filterable" + description: "__Filterable__ The city for this child account's billing address." + type: "string" + state: + maxLength: 24 + example: "CA" + x-linode-filterable: true + x-akamai: + labels: + - "Filterable" + description: "__Filterable__ The state or province for the billing address (`address_1` and `address_2, if applicable`). If in the United States (US) or Canada (CA), this is the two-letter ISO 3166 State or Province code.\n\n__Note__. If this is a US military address, use state abbreviations (AA, AE, AP)." + type: "string" + credit_card: + readOnly: true + additionalProperties: false + description: "__Read-only__ Information for the credit card you've assigned to this child account." + type: "object" + properties: + expiry: + type: "string" + description: "The expiration month and year of the credit card." + example: "11/2024" + last_four: + description: "The last four digits of the credit card." + type: "string" + example: 1111 + euuid: + readOnly: true + example: "A1BC2DEF-34GH-567I-J890KLMN12O34P56" + format: "uuid" + type: "string" + description: "__Read-only__ An external, unique identifier that Akamai assigned to the child account." + address_1: + description: "__Filterable__ First line of this child account's billing address." + type: "string" + x-akamai: + labels: + - "Filterable" + example: "123 Main Street" + maxLength: 64 + x-linode-filterable: true + country: + x-linode-filterable: true + example: "US" + x-akamai: + labels: + - "Filterable" + description: "__Filterable__ The two-letter ISO 3166 country code for this child account's billing address." + type: "string" + last_name: + maxLength: 50 + example: "Smith" + x-linode-filterable: true + type: "string" + description: "__Filterable__ The last name of the owner of this child account. It can't include any of these characters: `<` `>` `(` `)` `\"` `=`." + x-linode-cli-display: 2 + x-akamai: + labels: + - "Filterable" + balance_uninvoiced: + x-linode-cli-display: 4 + type: "number" + description: "__Read-only__ This child account's current estimated invoice in US dollars. This is not your final invoice balance. Transfer charges are not included in the estimate." + readOnly: true + example: 145 + email: + x-akamai: + labels: + - "Filterable" + x-linode-cli-display: 3 + type: "string" + description: "__Filterable__ The email address of the owner of this child account." + x-linode-filterable: true + example: "john.smith@linode.com" + maxLength: 128 + billing_source: + description: "__Read-only__ The source of service charges for this account, as determined by its relationship with Akamai. The API returns a value of `external` to describe a child account in a parent-child account environment." + type: "string" + enum: + - "external" + example: "external" + readOnly: true + company: + x-linode-filterable: true + maxLength: 128 + example: "Acme" + x-akamai: + labels: + - "Filterable" + type: "string" + description: "__Filterable__ The company name for the owner of this child account. It can't include any of these characters: `<` `>` `(` `)` `\"` `=`. You can't change this value yourself. We use it to create the proxy users that a parent account uses to access a child account. Talk to your account team if you need to change this value." + phone: + type: "string" + description: "__Filterable__ The phone number for the owner of this child account." + x-akamai: + labels: + - "Filterable" + maxLength: 32 + example: "858-555-1212" + x-linode-filterable: true + tax_id: + maxLength: 25 + example: "ATU99999999" + description: "The tax identification number for this child account. Use this for tax calculations in some countries. If you live in a country that doesn't collect taxes, ensure this is an empty string (`\"\"`)." + type: "string" + type: "object" + description: "Child account object." + added-post-client: + allOf: + - + properties: + redirect_uri: + type: "string" + description: "The location a successful log in from [login.linode.com](https://login.linode.com) should be redirected to for this client. The receiver of this redirect should be ready to accept an OAuth exchange code and finish the OAuth exchange." + format: "url" + x-linode-cli-display: 5 + example: "https://example.org/oauth/callback" + secret: + type: "string" + description: "__Read-only__ The OAuth Client secret, used in the OAuth exchange. This is returned as `` except when an OAuth Client is created or its secret is reset. This is a secret, and should not be shared or disclosed publicly." + readOnly: true + example: "" + id: + readOnly: true + example: "2737bf16b39ab5d7b4a1" + x-linode-cli-display: 1 + description: "__Read-only__ The OAuth Client ID. This is used to identify the client, and is a publicly-known value (it is not a secret)." + type: "string" + status: + x-linode-cli-color: + suspended: "red" + default_: "white" + enum: + - "active" + - "disabled" + - "suspended" + example: "active" + readOnly: true + description: "__Read-only__ The status of this application. `active` by default." + type: "string" + x-linode-cli-display: 3 + thumbnail_url: + nullable: true + type: "string" + description: "__Read-only__ The URL where this client's thumbnail may be viewed, or `null` if this client does not have a thumbnail set." + format: "url" + example: "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" + readOnly: true + public: + example: false + x-linode-filterable: true + type: "boolean" + description: "__Filterable__ If this is a public or private OAuth Client. Public clients have a slightly different authentication workflow than private clients. See the [OAuth spec](https://oauth.net/2/) for more details." + x-linode-cli-display: 4 + default: false + x-akamai: + labels: + - "Filterable" + label: + minLength: 1 + x-akamai: + labels: + - "Filterable" + x-linode-cli-display: 2 + description: "__Filterable__ The name of this application. This will be presented to users when they are asked to grant it access to their Account." + type: "string" + x-linode-filterable: true + example: "Test_Client_1" + maxLength: 512 + x-akamai: + file-path: "schemas/oauth-client.yaml" + description: "A third-party application registered to Linode that users may log into with their Linode account through our authentication server at [login.linode.com](https://login.linode.com). Using an OAuth Client, a third-party developer may be given access to some, or all, of a User's account for the purposes of their application." + type: "object" + additionalProperties: false + required: + - "label" + - "redirect_uri" + x-akamai: + file-path: "schemas/added-post-client.yaml" + payment-method: + additionalProperties: false + properties: + data: + oneOf: + - + x-linode-ref-name: "Credit Card" + title: "Credit card" + properties: + card_type: + description: "__Read-only__ The type of credit card." + type: "string" + example: "Discover" + readOnly: true + last_four: + type: "string" + description: "__Read-only__ The last four digits of the credit card number." + readOnly: true + example: "1234" + expiry: + example: "06/2022" + readOnly: true + type: "string" + description: "__Read-only__ The expiration month and year of the credit card." + format: "MM/YYYY" + x-akamai: + file-path: "schemas/credit-card-data.yaml" + type: "object" + description: "Credit card information." + additionalProperties: false + - + type: "object" + description: "Google Pay information." + properties: + last_four: + example: "1234" + readOnly: true + description: "__Read-only__ The last four digits of the credit card number." + type: "string" + expiry: + readOnly: true + example: "06/2022" + format: "MM/YYYY" + type: "string" + description: "__Read-only__ The expiration month and year of the credit card." + card_type: + readOnly: true + example: "Discover" + type: "string" + description: "__Read-only__ The type of credit card." + x-akamai: + file-path: "schemas/google-pay-data.yaml" + x-linode-ref-name: "Google Pay" + title: "Google Pay" + additionalProperties: false + - + title: "Paypal" + x-linode-ref-name: "Paypal" + additionalProperties: false + type: "object" + description: "PayPal information." + x-akamai: + file-path: "schemas/paypal-data.yaml" + properties: + paypal_id: + readOnly: true + example: "ABC1234567890" + type: "string" + description: "__Read-only__ PayPal Merchant ID associated with your PayPal account." + email: + type: "string" + description: "__Read-only__ The email address associated with your PayPal account." + readOnly: true + example: "example@linode.com" + x-linode-cli-format: "json" + x-linode-cli-display: 4 + created: + example: "2018-01-15T00:01:01" + readOnly: true + description: "__Read-only__ When the Payment Method was added to the Account." + type: "string" + format: "date-time" + is_default: + type: "boolean" + description: "Whether this Payment Method is the default method for automatically processing service charges." + x-linode-cli-display: 3 + example: true + id: + x-linode-cli-display: 1 + description: "The unique ID of this Payment Method." + type: "integer" + example: 123 + type: + example: "credit_card" + enum: + - "credit_card" + - "google_pay" + - "paypal" + x-linode-cli-display: 2 + type: "string" + description: "The type of Payment Method." + x-akamai: + file-path: "schemas/payment-method.yaml" + type: "object" + description: "Payment Method Response Object." + paypal-execute: + additionalProperties: false + properties: + payer_id: + description: "The PayerID returned by PayPal during the transaction authorization process." + type: "string" + example: "ABCDEFGHIJKLM" + payment_id: + example: "PAY-1234567890ABCDEFGHIJKLMN" + description: "The PaymentID returned from [Stage a PayPal payment](https://techdocs.akamai.com/linode-api/reference/post-pay-pal-payment) that has been approved with PayPal." + type: "string" + x-akamai: + file-path: "schemas/paypal-execute.yaml" + type: "object" + description: "An object representing an execution of Payment to PayPal to capture the funds and credit your Linode Account." + required: + - "payer_id" + - "payment_id" + added-post-beta-program: + additionalProperties: false + properties: + id: + x-linode-cli-display: 1 + description: "The unique identifier of the Beta Program." + type: "string" + example: "example_open" + x-akamai: + file-path: "schemas/added-post-beta-program.yaml" + description: "The Beta Program ID to enroll in for your Account." + type: "object" + required: + - "id" + oauth-client: + additionalProperties: false + properties: + secret: + readOnly: true + example: "" + type: "string" + description: "__Read-only__ The OAuth Client secret, used in the OAuth exchange. This is returned as `` except when an OAuth Client is created or its secret is reset. This is a secret, and should not be shared or disclosed publicly." + id: + x-linode-cli-display: 1 + description: "__Read-only__ The OAuth Client ID. This is used to identify the client, and is a publicly-known value (it is not a secret)." + type: "string" + readOnly: true + example: "2737bf16b39ab5d7b4a1" + redirect_uri: + example: "https://example.org/oauth/callback" + x-linode-cli-display: 5 + format: "url" + type: "string" + description: "The location a successful log in from [login.linode.com](https://login.linode.com) should be redirected to for this client. The receiver of this redirect should be ready to accept an OAuth exchange code and finish the OAuth exchange." + public: + x-linode-cli-display: 4 + x-akamai: + labels: + - "Filterable" + default: false + description: "__Filterable__ If this is a public or private OAuth Client. Public clients have a slightly different authentication workflow than private clients. See the [OAuth spec](https://oauth.net/2/) for more details." + type: "boolean" + example: false + x-linode-filterable: true + label: + minLength: 1 + type: "string" + description: "__Filterable__ The name of this application. This will be presented to users when they are asked to grant it access to their Account." + x-akamai: + labels: + - "Filterable" + x-linode-cli-display: 2 + x-linode-filterable: true + example: "Test_Client_1" + maxLength: 512 + thumbnail_url: + readOnly: true + example: "https://api.linode.com/v4/account/clients/2737bf16b39ab5d7b4a1/thumbnail" + format: "url" + nullable: true + description: "__Read-only__ The URL where this client's thumbnail may be viewed, or `null` if this client does not have a thumbnail set." + type: "string" + status: + x-linode-cli-color: + suspended: "red" + default_: "white" + readOnly: true + enum: + - "active" + - "disabled" + - "suspended" + example: "active" + x-linode-cli-display: 3 + description: "__Read-only__ The status of this application. `active` by default." + type: "string" + x-akamai: + file-path: "schemas/oauth-client.yaml" + description: "A third-party application registered to Linode that users may log into with their Linode account through our authentication server at [login.linode.com](https://login.linode.com). Using an OAuth Client, a third-party developer may be given access to some, or all, of a User's account for the purposes of their application." + type: "object" + added-post-promo-credit: + type: "object" + properties: + promo_code: + maxLength: 32 + minLength: 1 + description: "The Promo Code." + type: "string" + x-akamai: + file-path: "schemas/added-post-promo-credit.yaml" + required: + - "promo_code" + additionalProperties: false + proxy-user-token: + description: "The token generated manually for a child account so its proxy user can access the API and CLI without going through an OAuth login." + type: "object" + x-akamai: + file-path: "schemas/proxy-user-token.yaml" + properties: + label: + example: "parent1_1234_2024-05-01T00:01:01" + maxLength: 100 + x-linode-filterable: true + minLength: 1 + x-linode-cli-display: 2 + x-akamai: + labels: + - "Filterable" + description: "__Filterable__ The name of the token. The API automatically sets this to `__