diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 00000000..216dfef0 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,11 @@ +[run] +branch = True +source = + maas/client +omit = + */testing.py + */tests/*.py + +[html] +title = + Coverage for python-libmaas diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..329b40dc --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +/debian export-ignore +/.git export-ignore +.gitignore export-ignore +.gitattributes export-ignore +.travis.yml export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..ca33b927 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,57 @@ +name: CI tests + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + lint: + runs-on: ubuntu-20.04 + steps: + - name: Repository checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: "3.6" + + - name: Install dependencies + run: | + pip install --upgrade pip tox + + - name: Lint + run: | + tox -e lint + + test: + runs-on: ubuntu-20.04 + strategy: + matrix: + python-version: + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" + steps: + - name: Repository checkout + uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + pip install --upgrade pip tox codecov + + - name: Test + run: | + tox -e py3 + codecov diff --git a/.github/workflows/cla-check.yml b/.github/workflows/cla-check.yml new file mode 100644 index 00000000..6b767cce --- /dev/null +++ b/.github/workflows/cla-check.yml @@ -0,0 +1,10 @@ +name: cla-check + +on: [pull_request] + +jobs: + cla-check: + runs-on: ubuntu-latest + steps: + - name: Check if CLA signed + uses: canonical/has-signed-canonical-cla@v2 diff --git a/.github/workflows/stale-cron.yaml b/.github/workflows/stale-cron.yaml new file mode 100644 index 00000000..f5579966 --- /dev/null +++ b/.github/workflows/stale-cron.yaml @@ -0,0 +1,9 @@ +name: Close inactive issues +on: + schedule: + - cron: "0 0 * * *" + +jobs: + close-issues: + uses: canonical/maas-github-workflows/.github/workflows/stale-cron.yaml@v0 + secrets: inherit diff --git a/.gitignore b/.gitignore index baa9aeb4..3451c7f4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ bin/ include/ local/ share/ +*.snap # PyInstaller # Usually these files are written by a python script from a template @@ -63,3 +64,38 @@ target/ # mkdocs site/ + +# Packaging +.pc/ + +# Editors +.vscode/ + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/ + + +# CMake +cmake-build-*/ + + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 94b7aa83..00000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: python -python: - - "3.5" - -install: - - pip install codecov tox - -script: - - tox -e py35,lint - -after_success: - - codecov --env TRAVIS_PYTHON_VERSION - -branches: - only: - - master diff --git a/LICENSE b/LICENSE index c20b2206..2c315702 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ -Alburnum MAAS Client is Copyright 2015-2016 Gavin Panella and Copyright -2015-2016 Canonical Ltd. +MAAS Client is Copyright 2015-2016 Gavin Panella and Copyright +2015-2017 Canonical Ltd. -Gavin Panella and Canonical Ltd. distributes the Alburnum MAAS Client +Gavin Panela and Canonical Ltd. distributes the MAAS Client source code under the GNU Affero General Public License, version 3 ("AGPLv3"). The full text of this licence is given below. diff --git a/Makefile b/Makefile index 83053c07..774315ab 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,10 @@ -PYTHON := python3.5 +python := python3 +snapcraft := SNAPCRAFT_BUILD_INFO=1 /snap/bin/snapcraft + +# --- + +install-dependencies: + if [ -x /usr/bin/snap ]; then sudo snap install --classic snapcraft; fi # --- @@ -6,16 +12,23 @@ develop: bin/python setup.py bin/python setup.py develop dist: bin/python setup.py README - bin/python setup.py egg_info sdist + bin/python setup.py sdist bdist_wheel -upload: bin/python setup.py README - bin/python setup.py egg_info sdist upload +upload: bin/python bin/twine setup.py README + bin/python setup.py sdist bdist_wheel + bin/twine upload dist/* test: bin/tox @bin/tox +integrate: bin/tox + @bin/tox -e integrate + +format: bin/tox + @bin/tox -e format,imports + lint: bin/tox - @bin/tox -e lint + @bin/tox -e lint,imports clean: $(RM) -r bin build dist include lib local share @@ -25,6 +38,15 @@ clean: find . -name '*.egg-info' -print0 | xargs -r0 $(RM) -r find . -name '*~' -print0 | xargs -r0 $(RM) $(RM) -r .eggs .tox .coverage TAGS tags + $(RM) pip-selfcheck.json + +# --- + +snap-clean: + $(snapcraft) clean + +snap: + $(snapcraft) # --- @@ -34,17 +56,36 @@ README: README.md docs: bin/mkdocs bin/mkdocs build --config-file doc.yaml --clean --strict +docs-to-github: bin/mkdocs + bin/mkdocs gh-deploy --config-file doc.yaml --clean + # --- bin/tox: bin/pip bin/pip install --quiet --ignore-installed tox bin/python bin/pip: - virtualenv --python=$(PYTHON) --quiet $(CURDIR) + virtualenv --python=$(python) --quiet $(CURDIR) bin/mkdocs: bin/pip bin/pip install --quiet --ignore-installed "mkdocs >= 0.14.0" +bin/twine: bin/pip + bin/pip install --quiet --ignore-installed twine + +# --- + +api-json-raw := $(wildcard maas/client/bones/testing/*.raw.json) +api-json := $(patsubst %.raw.json,%.json,$(api-json-raw)) + +pretty: $(api-json) + +%.json: %.pretty.json + cp $^ $@ + +%.pretty.json: %.raw.json + scripts/prettify-api-desc-doc < $^ > $@ + # --- -.PHONY: develop dist docs test lint clean +.PHONY: install-dependencies develop dist docs docs-to-github test integrate lint clean pretty snap snap-clean diff --git a/README b/README index 229b0735..3b292a58 100644 --- a/README +++ b/README @@ -1,45 +1,67 @@ -python-libmaas -============== +# python-libmaas -Python client API library made especially for -`MAAS `__. +Python client API library made especially for [MAAS][]. -This was begun by a core MAAS developer, Gavin Panella, on his own time, -but is now maintained by the core MAAS team at Canonical. It is licensed -under the GNU Affero GPLv3, the same as MAAS itself. +[![CI tests](https://github.com/canonical/python-libmaas/workflows/CI%20tests/badge.svg)](https://github.com/canonical/python-libmaas/actions?query=workflow%3A%22CI+tests%22) +[![codecov.io](https://codecov.io/github/canonical/python-libmaas/coverage.svg?branch=master)](https://codecov.io/github/maas/python-libmaas?branch=master) -|Build Status| |codecov.io| -Some of the code in here has come from MAAS, upon which Canonical Ltd -has the copyright. Gavin Panella licenses his parts under the AGPLv3, -and MAAS is also under the AGPLv3, so everything should be good. +## Installation -Installation ------------- +All the dependencies are declared in `setup.py` so this can be installed +with [pip](https://pip.pypa.io/). Python 3.5+ is required. -All the dependencies are declared in ``setup.py`` so this can be -installed with `pip `__. Python 3.5 is required. +When working from master it can be helpful to use a virtualenv: -When working from trunk it can be helpful to use ``virtualenv``: + $ python3 -m venv ve && source ve/bin/activate + $ pip install git+https://github.com/canonical/python-libmaas.git + $ maas --help -:: +Releases are periodically made to [PyPI](https://pypi.python.org/) but, +at least for now, it makes more sense to work directly from trunk. - $ virtualenv --python=python3.5 amc && source amc/bin/activate - $ pip install git+https://github.com/maas/python-libmaas.git - $ maas --help -Releases are periodically made to `PyPI `__ -but, at least for now, it makes more sense to work directly from trunk. +## Documentation + +Documentation can be generated with `make docs` which publishes into the +`site` directory. Recent documentation is also published to the +[MAAS Client Library & CLI documentation][docs] site. + + +## Development + +It's pretty easy to start hacking on _python-libmaas_: + + $ git clone git@github.com:maas/python-libmaas.git + $ cd python-libmaas + $ make develop + $ make test + +Installing [IPython][] is generally a good idea too: + + $ bin/pip install -UI IPython + +Pull requests are welcome but authors need to sign the [Canonical +contributor license agreement][CCLA] before those PRs can be merged. + + +## History & licence + +In short: [AGPLv3][]. + +_python-libmaas_ was begun by a core MAAS developer, Gavin Panella, on +his own time, but is now maintained by the core MAAS team at Canonical. +It is licensed under the GNU Affero GPLv3, the same as MAAS itself. + +Some of the code in here has come from MAAS, upon which Canonical Ltd +has the copyright. Gavin Panella licenses his parts under the AGPLv3, +and MAAS is also under the AGPLv3, so everything should be good. + -Documentation -------------- +[MAAS]: https://maas.io/ +[docs]: http://maas.github.io/python-libmaas/ -Documentation can be generated with ``make docs`` which publishes into -the ``site`` directory. Recent documentation is also published to the -`MAAS Client Library & CLI -documentation `__ site. +[CCLA]: https://www.ubuntu.com/legal/contributors +[AGPLv3]: https://www.gnu.org/licenses/agpl-3.0.html -.. |Build Status| image:: https://travis-ci.org/maas/python-libmaas.svg?branch=master - :target: https://travis-ci.org/maas/python-libmaas -.. |codecov.io| image:: https://codecov.io/github/maas/python-libmaas/coverage.svg?branch=master - :target: https://codecov.io/github/maas/python-libmaas?branch=master +[IPython]: https://ipython.org/ diff --git a/README.md b/README.md deleted file mode 100644 index 661a05a9..00000000 --- a/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# python-libmaas - -Python client API library made especially for [MAAS][1]. - -This was begun by a core MAAS developer, Gavin Panella, on his own time, -but is now maintained by the core MAAS team at Canonical. It is licensed -under the GNU Affero GPLv3, the same as MAAS itself. - -[![Build Status](https://travis-ci.org/maas/python-libmaas.svg?branch=master)](https://travis-ci.org/maas/python-libmaas) -[![codecov.io](https://codecov.io/github/maas/python-libmaas/coverage.svg?branch=master)](https://codecov.io/github/maas/python-libmaas?branch=master) - -Some of the code in here has come from MAAS, upon which Canonical Ltd -has the copyright. Gavin Panella licenses his parts under the AGPLv3, -and MAAS is also under the AGPLv3, so everything should be good. - - -## Installation - -All the dependencies are declared in `setup.py` so this can be installed -with [pip](https://pip.pypa.io/). Python 3.5 is required. - -When working from trunk it can be helpful to use `virtualenv`: - - $ virtualenv --python=python3.5 amc && source amc/bin/activate - $ pip install git+https://github.com/maas/python-libmaas.git - $ maas --help - -Releases are periodically made to [PyPI](https://pypi.python.org/) but, -at least for now, it makes more sense to work directly from trunk. - - -## Documentation - -Documentation can be generated with `make docs` which publishes into the -`site` directory. Recent documentation is also published to the -[MAAS Client Library & CLI documentation][2] site. - - -[1]: https://maas.ubuntu.com/ -[2]: http://maas.github.io/python-libmaas/ diff --git a/README.md b/README.md new file mode 120000 index 00000000..100b9382 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..98e04531 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,14 @@ +python-libmaas (0.6.0-0ubuntu1) bionic; urgency=medium + + * New upstream release + * d/p/{00-disable_bson_install_requires,01-fix_setup_py_lists}.patch: Drop. + merged upstream. + * debian/watch: Cleanup unneeded comments. + + -- Andres Rodriguez Tue, 06 Feb 2018 21:15:00 -0500 + +python-libmaas (0.5.0-0ubuntu1) bionic; urgency=medium + + * Initial release (LP: #1747328) + + -- Andres Rodriguez Sun, 04 Feb 2018 20:45:42 -0500 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +10 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..40fe1c62 --- /dev/null +++ b/debian/control @@ -0,0 +1,26 @@ +Source: python-libmaas +Section: python +Priority: optional +Maintainer: Andres Rodriguez +Build-Depends: debhelper (>= 10), dh-python, python3-all, python3-setuptools +Standards-Version: 4.1.3 +Homepage: https://github.com/canonical/python-libmaas +X-Python3-Version: >= 3.2 + +Package: python3-libmaas +Architecture: all +Depends: python3-aiohttp, + python3-argcomplete, + python3-bson, + python3-colorclass, + python3-oauthlib, + python3-tz, + python3-yaml, + python3-terminaltables, + ${python3:Depends}, + ${misc:Depends} +Description: MAAS asyncio client library (Python 3) + The MAAS Python Client library provides an asyncio based library + to interact with MAAS. + . + This package installs the library for Python 3. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..8af8f6a0 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,26 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: python-libmaas +Source: https://github.com/canonical/python-libmaas + +Files: * +Copyright: 2017-2018 Canonical Ltd. +License: AGPL-3.0+ + +Files: debian/* +Copyright: 2018 Andres Rodriguez + 2018 Canonical Ltd. +License: AGPL-3.0+ + +License: AGPL-3.0+ + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + . + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + . + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . diff --git a/debian/files b/debian/files new file mode 100644 index 00000000..1ee54ad2 --- /dev/null +++ b/debian/files @@ -0,0 +1 @@ +python-libmaas_0.6.0-0ubuntu1_source.buildinfo python optional diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 00000000..e69de29b diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..8cddcb21 --- /dev/null +++ b/debian/rules @@ -0,0 +1,24 @@ +#!/usr/bin/make -f +# See debhelper(7) (uncomment to enable) +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + +export PYBUILD_NAME=python-libmaas + +%: + dh $@ --with python3 --buildsystem=pybuild + + +override_dh_auto_install: + dh_auto_install + + # Remove binary that's created by the setup.py + rm -rf $(CURDIR)/debian/python3-libmaas/usr/bin/maas + +override_dh_auto_build: + # Do nothing. We have nothing to build, hence disabling + # the build process. + +override_dh_auto_test: + # Do nothing. Tests require running daemons, hence + # disable them during packaging building. diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 00000000..cb61fa52 --- /dev/null +++ b/debian/source/options @@ -0,0 +1 @@ +extend-diff-ignore = "^[^/]*[.]egg-info/" diff --git a/debian/watch b/debian/watch new file mode 100644 index 00000000..929cbb7a --- /dev/null +++ b/debian/watch @@ -0,0 +1,10 @@ +# Compulsory line, this is a version 4 file +version=4 + +# PGP signature mangle, so foo.tar.gz has foo.tar.gz.sig +#opts="pgpsigurlmangle=s%$%.sig%" + +# GitHub hosted projects +opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%python-libmaas-$1.tar.gz%" \ + https://github.com/canonical/python-libmaas/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian uupdate diff --git a/doc.yaml b/doc.yaml index cc633985..d39de881 100644 --- a/doc.yaml +++ b/doc.yaml @@ -3,18 +3,20 @@ markdown_extensions: - codehilite - sane_lists - smarty -repo_url: https://github.com/maas/python-libmaas +repo_url: https://github.com/canonical/python-libmaas site_name: MAAS Client Library & CLI strict: true theme: readthedocs use_directory_urls: false pages: - Home: index.md - - Bones: - - Home: bones/index.md - - Viscera: - - Home: viscera/index.md - - Getting started: viscera/getting-started.md - - Nodes: viscera/nodes.md - - Events: viscera/events.md - - Other objects: viscera/other.md + - Client: + - Introduction: client/index.md + - Nodes: client/nodes.md + - Networking: client/networking.md + - Interfaces: client/interfaces.md + - Events: client/events.md + - Others: client/other.md + - Development: + - Release checklist: development/releasing.md + - Adding an object: development/adding-an-object.md diff --git a/doc/bones/index.md b/doc/bones/index.md deleted file mode 100644 index 42e7e925..00000000 --- a/doc/bones/index.md +++ /dev/null @@ -1,51 +0,0 @@ -# _Bones_: Low-level Python client API - -You may prefer the [higher-level API _viscera_](../viscera/index.md), -but maybe you need to do something that you can't do in _viscera_ yet -(please file a bug!), or you're developing _viscera_ itself (which uses -_bones_ behind the scenes). - - -## Some example code - -```python -#!/usr/bin/env python3.5 - -from http import HTTPStatus -from pprint import pprint - -from maas.client import bones - - -profile, session = bones.SessionAPI.login( - "http://localhost:5240/MAAS/", username="alice", - password="wonderland") - -# Create a tag if it doesn't exist. -tag_name = "gryphon" -tag_comment = "Gryphon's Stuff" -try: - tag = session.Tag.read(name=tag_name) -except bones.CallError as error: - if error.status == HTTPStatus.NOT_FOUND: - tag = session.Tags.new( - name=tag_name, comment=tag_comment) - else: - raise - -# List all the tags. -print(">>> Tags.list()") -pprint(session.Tags.list()) - -# Get the system IDs for all nodes. -print(">>> Nodes.list()") -all_nodes_system_ids = [ - node["system_id"] for node in session.Nodes.list() -] -pprint(all_nodes_system_ids) - -# Associate the tag with all nodes. -print(">>> Tag.update_nodes()") -pprint(session.Tag.update_nodes( - name=tag["name"], add=all_nodes_system_ids)) -``` diff --git a/doc/client/events.md b/doc/client/events.md new file mode 100644 index 00000000..f8d2e658 --- /dev/null +++ b/doc/client/events.md @@ -0,0 +1,34 @@ +

Events

+ +Events are similar to other client objects... but a little different +too. The only way to get events is by the ``query`` method: + +```pycon +>>> events = client.events.query() +``` + +This accepts a plethora of optional arguments to narrow down the results: + +```pycon +>>> events = client.events.query(hostnames={"foo", "bar"}) +>>> events = client.events.query(domains={"example.com", "maas.io"}) +>>> events = client.events.query(zones=["red", "blue"]) +>>> events = client.events.query(macs=("12:34:56:78:90:ab", )) +>>> events = client.events.query(system_ids=…) +>>> events = client.events.query(agent_name=…) +>>> events = client.events.query(level=…) +>>> events = client.events.query(after=…, limit=…) +>>> events = client.events.query(owner=…) +``` + +These arguments can be combined to narrow the results even further. + +The ``level`` argument is a little special. It's a choice from a +predefined set. For convenience, those choices are available in +``client.events``: + +```pycon +>>> events = client.events.query(level=client.events.ERROR) +``` + +but you can also pass in the string "ERROR" or the number 40. diff --git a/doc/client/index.md b/doc/client/index.md new file mode 100644 index 00000000..d6f6e9ad --- /dev/null +++ b/doc/client/index.md @@ -0,0 +1,110 @@ +

The Web API client

+ +Calling ``maas.client.connect`` or ``maas.client.login`` (MAAS 2.2+ +only) will return a ``maas.client.facade.Client`` instance. This +provides an easy to understand starting point for working with MAAS's +Web API. + + +## An example + +```python +#!/usr/bin/env python3.6 + +import maas.client + +# Replace … with an API key previously obtained by hand from +# http://$host:$port/MAAS/account/prefs/. +client = maas.client.connect( + "http://localhost:5240/MAAS/", apikey="…") + +# Get a reference to self. +myself = client.users.whoami() +assert myself.is_admin, "%s is not an admin" % myself.username + +# Check for a MAAS server capability. +version = client.version.get() +assert "devices-management" in version.capabilities + +# Check the default OS and distro series for deployments. +print(client.maas.get_default_os()) +print(client.maas.get_default_distro_series()) + +# Set the HTTP proxy. +client.maas.set_http_proxy("http://localhost:3128") + +# Allocate and deploy a machine. +machine = client.machines.allocate() +machine.deploy() +``` + + +### Using `login` + +Alternatively, a client can be obtained from a username and password, +replacing the call to `connect` above. This only works in MAAS 2.2 and +above; below that a `LoginNotSupported` exception will be raised. + +```python +client = login( + "http://localhost:5240/MAAS/", + username="foo", password="bar", +) +``` + + +### Again, but asynchronous + +At first glance _python-libmaas_ appears to be a blocking API, but it's +actually asynchronous under the skin, based on [asyncio][]. If you call +into _python-libmaas_ from within a running event loop it will behave +asynchronously, but called from outside it behaves synchronously, and +blocks. + +Using _python-libmaas_ interactively, when exploring the library or +trying something out, is familiar and natural because it behaves as a +synchronous, blocking API. This mode can be used of in scripts too, but +the same code can be easily repurposed for use in an asynchronous, +non-blocking application. + +Below shows the earlier example but implemented in an asynchronous +style. Note the use of the ``asynchronous`` decorator: this is used +heavily in _python-libmaas_ — along with the ``Asynchronous`` metaclass +— to create the automatic blocking/not-blocking behaviour. + +```python +#!/usr/bin/env python3.6 + +from maas.client import login +from maas.client.utils.async import asynchronous + +@asynchronous +async def work_with_maas(): + client = await login( + "http://eucula.local:5240/MAAS/", + username="gavin", password="f00b4r") + + # Get a reference to self. + myself = await client.users.whoami() + assert myself.is_admin, "%s is not an admin" % myself.username + + # Check for a MAAS server capability. + version = await client.version.get() + assert "devices-management" in version.capabilities + + # Check the default OS and distro series for deployments. + print(await client.maas.get_default_os()) + print(await client.maas.get_default_distro_series()) + + # Set the HTTP proxy. + await client.maas.set_http_proxy("http://localhost:3128") + + # Allocate and deploy a machine. + machine = await client.machines.allocate() + await machine.deploy() + +work_with_maas() +``` + + +[asyncio]: https://docs.python.org/3/library/asyncio.html diff --git a/doc/client/interfaces.md b/doc/client/interfaces.md new file mode 100644 index 00000000..21219487 --- /dev/null +++ b/doc/client/interfaces.md @@ -0,0 +1,204 @@ +

Interfaces

+ +Given an ``Node`` instance bound to your MAAS server, you can +view and modify its interface configuration. This applies to all ``Machine``, +``Device``, ``RackController``, and ``RegionController``. + +## Read interfaces + +All ``Node`` objects have an ``interfaces`` property that provide a sequence of +all ``Interface``'s on the ``Node``. + +```pycon +>>> machine.interfaces +>]> +>>> machine.boot_interface +> +``` + +On bond, VLAN, and bridge interfaces you can get the parents that make the +interface. You can also go the other direction and view the children interfaces +that are using this interface. + +**Note:** Parent and children objects are unloaded so they must be loaded to +access the properties of the object. + +```pycon +>>> bond.parents + (unloaded)>, + (unloaded)>, + ]> +>>> ens3 = bond.parents[0] +>>> ens3.loaded +False +>>> ens3.refresh() +>>> ens3.type + +>>> ens3.children + (unloaded)>, + ]> +``` + +## Get interface by name + +The ``interfaces`` property on ``Node`` gives you access to all interfaces on +the node. Sometimes you want to access the interface objects by name. +``by_name`` and ``get_by_name`` are helpers on ``Interfaces`` that help. + +```pycon +>>> machine.interfaces.by_name +{'bond0': >, + 'ens3': >, + 'ens8': >} +>>> bond = machine.interfaces.get_by_name('bond0') +>>> bond +> +``` + +## Read IP configuration + +Every ``Interface`` has a ``links`` property that provides all the IP +information on how the interface is configured. + +```pycon +>>> bond.links + + subnet=>>]> +``` + +## Create physical + +Creation of interfaces is done directly on the ``interfaces`` property of a +``Node``. Physical interface is the default type for the ``create`` method so +only ``mac_address`` is required. + +```pycon +>>> new_phy = machine.interfaces.create(mac_address="00:11:22:aa:bb:cc") +>>> new_phy +> +``` + +By default the interface is created disconnected. To create it the interface +with it connected to a VLAN pass the ``vlan`` parameter. + +```pycon +>>> default_vlan = client.fabrics.get_default().vlans.get_default() +>>> new_phy = machine.interfaces.create( +... mac_address="00:11:22:aa:bb:cc", vlan=default_vlan) +>>> new_phy +> +>>> new_phy.vlan + +``` + +## Create bond + +Bond creation is the same as creating a physical interface but an +``InterfaceType`` is provided with options specific for a bond. + +```pycon +>>> new_bond = machine.interfaces.create( +... InterfaceType.BOND, name='bond0', parents=machine.interfaces, +... bond_mode='802.3ad') +>>> new_bond +> +>>> new_bond.params +{'bond_downdelay': 0, + 'bond_lacp_rate': 'slow', + 'bond_miimon': 100, + 'bond_mode': '802.3ad', + 'bond_updelay': 0, + 'bond_xmit_hash_policy': 'layer2'} +``` + +## Create vlan + +VLAN creation only requires a single parent and a tagged VLAN to connect +the interface to. + +```pycon +>>> default_fabric = client.fabrics.get_default() +>>> vlan_10 = default_fabric.vlans.create(10) +>>> vlan_nic = machine.interfaces.create( +... InterfaceType.VLAN, parent=new_bond, vlan=vlan_10) +>>> vlan_nic +> +``` + +## Create bridge + +Bridge creation only requires the name and parent interface you want the +bridge to be created on. + +```pycon +>>> bridge_nic = machine.interfaces.create( +... InterfaceType.BRIDGE, name='br0', parent=vlan_nic) +>>> bridge_nic +> +``` + +## Update interface + +To update an interface just changing the properties of the interface and +calling ``save`` is all that is required. + +```pycon +>>> new_bond.name = 'my-bond' +>>> new_bond.params['bond_mode'] = 'active-backup' +>>> new_bond.save() +``` + +## Change IP configuration + +To adjust the IP configuration on a specific interface ``create`` on the +``links`` property and ``delete`` on the ``InterfaceLink`` can be used. + +```pycon +>>> new_bond.links.create(LinkMode.AUTO, subnet=subnet) + + subnet=>> +>>> new_bond.links[-1].delete() +>>> new_bond.links.create( +... LinkMode.STATIC, subnet=subnet, ip_address='192.168.122.1') + + subnet=>> +>>> new_bond.links[-1].delete() +``` + +## Disconnect interface + +To completely mark an interface as disconnected and remove all configuration +the ``disconnect`` call makes this easy. + +``` +>>> new_bond.disconnect() +``` + +## Delete interface + +``delete`` exists directly on the ``Interface`` object so deletion is simple. + +```pycon +>>> new_bond.delete() +``` diff --git a/doc/client/networking.md b/doc/client/networking.md new file mode 100644 index 00000000..d19a2520 --- /dev/null +++ b/doc/client/networking.md @@ -0,0 +1,130 @@ +

Fabrics, VLANs, Subnets, Spaces, IP Ranges, Static Routes

+ +Given a ``Client`` instance bound to your MAAS server, you can +interrogate your entire networking configuration. + +## Read networking + +``fabrics``, ``subnets``, ``spaces``, ``ip_ranges``, and ``static_routes`` is +exposed directly on your ``Client`` instance. ``vlans`` are nested under each +``Fabric``. + +```pycon +>>> fabrics = client.fabrics.list() +>>> len(fabrics) +1 +>>> default_fabric = fabrics.get_default() +>>> default_fabric.name +'fabric-0' +>>> default_fabric.vlans +]> +>>> for vlan in default_fabric.vlans: +... print(vlan) +... + +>>> +``` + +Get a specific subnet and view the ``Vlan`` and ``Fabric`` that it is +assigned to. Going up the tree from ``Vlan`` to ``Fabric`` results in an +unloaded ``Fabric``. Calling ``refresh`` on ``Fabric`` will load the object +from MAAS. + + +```pycon +>>> vm_subnet = client.subnets.get('192.168.122.0/24') +>>> vm_subnet.cidr +'192.168.122.0/24' +>>> vm_subnet.vlan + +>>> fabric = vm_subnet.vlan.fabric +>>> fabric + +>>> fabric.refresh() +>>> fabric.vlans +Traceback (most recent call last): +... +ObjectNotLoaded: cannot access attribute 'vlans' of object 'Fabric' +>>> fabric.is_loaded +False +>>> fabric.refresh() +>>> fabric.is_loaded +True +>>> fabric.vlans +]> +``` + +Access to ``spaces``, ``ip_ranges``, and ``static_routes`` works similarly. + +```pycon +>>> client.spaces.list() +>>> client.ip_ranges.list() +>>> client.static_routes.list() +``` + +## Create fabric & vlan + +Creating a new fabric and vlan is done directly from each set of objects on +the ``Client`` respectively. + +```pycon +>>> new_fabric = client.fabrics.create() +>>> new_fabric.name +'fabric-2' +>>> new_vlan = new_fabric.vlans.create(20) +>>> new_vlan + +>>> new_vlan.fabric + +``` + +## Create subnet + +Create a new subnet and assign it to an existing vlan. + +```pycon +>>> new_subnet = client.subnets.create('192.168.128.0/24', new_vlan) +>>> new_subnet.cidr +'192.168.128.0/24' +>>> new_subnet.vlan + +``` + +## Update subnet + +Quickly move the newly created subnet from vlan to default fabric +untagged vlan. + +```pycon +>>> default_fabric = client.fabrics.get_default() +>>> untagged = default_fabric.vlans.get_default() +>>> new_subnet.vlan = untagged +>>> new_subnet.save() +>>> new_subnet.vlan + +``` + +## Delete subnet + +``delete`` exists directly on the ``Subnet`` object so deletion is simple. + +```pycon +>>> new_subnet.delete() +>>> +``` + +## Enable DHCP + +Create a new dynamic IP range and turn DHCP on the selected +rack controller. + +```pycon +>>> fabric = client.fabrics.get_default() +>>> untagged = fabric.vlans.get_default() +>>> new_range = client.ip_ranges.create( +... '192.168.122.100', '192.168.122.200', type=IPRangeType.DYNAMIC) +>>> rack = client.rack_controllers.list()[0] +>>> untagged.dhcp_on = True +>>> untagged.primary_rack = rack +>>> untagged.save() +``` diff --git a/doc/client/nodes.md b/doc/client/nodes.md new file mode 100644 index 00000000..2a3f308f --- /dev/null +++ b/doc/client/nodes.md @@ -0,0 +1,296 @@ +

Machines, devices, racks, and regions

+ +Given a ``Client`` instance bound to your MAAS server, you can +interrogate your nodes. + +## Read nodes + +Each node type exists on the client: ``machines``, ``devices``, +``rack_controllers``, ``region_controllers``. + +```pycon +>>> client.machines.list() +]> +>>> client.devices.list() + +>>> client.rack_controllers.list() +]> +>>> client.region_controllers.list() +]> +``` + +Easily iterate through the machines. + +```pycon +>>> for machine in client.machines.list(): +... print(repr(machine)) + +``` + +Get a machine from its system_id. + +```pycon +>>> machine = client.machines.get(system_id="pncys4") +>>> machine + +``` + +Machines — and devices, racks, and regions — have many useful +attributes: + +```pycon +>>> machine.architecture +'amd64/generic' +>>> machine.cpus +4 +``` + +Don't forget to try using tab-completion — the objects have been +designed to be particularly friendly for interactive use — or +``dir(machine)`` to find out what other fields and methods are +available. + +## Create nodes + +Create a machine in MAAS. The architecture, MAC addresses, and power type are +required fields. + +```pycon +>>> machine = client.machines.create( +... "amd64", ["00:11:22:33:44:55", "AA:BB:CC:DD:EE:FF"], "manual") + +``` + +Normally you need to pass in power parameter so MAAS can talk to the BMC. + +```pycon +>>> machine = client.machines.create( +... "amd64", ["00:11:22:33:44:55", "AA:BB:CC:DD:EE:FF"], "ipmi", { +... "power_address": "10.245.0.10", +... "power_user": "root", +... "power_pass": "calvin", +... }) +>>> machine + +>>> machine.status + +``` + +## Updating nodes + +Updating a machine is as simple as modifying the attribute and saving. + +```pycon +>>> machine.hostname = 'my-machine' +>>> machine.architecture = 'i386/generic' +>>> machine.save() +``` + +## Deleting nodes + +Delete a machine is simple as calling delete on the machine object. + +```pycon +>>> machine.delete() +``` + +## Assigning tags + +Assigning tags to a machine is as simple as calling `add` or `remove` on +`tags` attribute. + +```pycon +>>> new_tag = client.tags.create('new') +>>> machine.tags.add(new_tag) +>>> machine.tags +]> +>>> machine.tags.remove(new_tag) +``` + +## Commissioning and testing + +Easily commission a machine and wait until it successfully completes. By +default the `commission` method waits until commissioning succeeds. + +```pycon +>>> machine.commission() +>>> machine.status +NodeStatus.READY +``` + +A more advanced asyncio based script that runs commissioning with extra scripts +and waits until all machines have successfully commissioned. + +```python +#!/usr/bin/env python3 + +import asyncio + +from maas.client import login +from maas.client.enum import NodeStatus +from maas.client.utils.async import asynchronous + + +@asynchronous +async def commission_all_machines(): + client = await login( + "http://eucula.local:5240/MAAS/", + username="gavin", password="f00b4r") + + # Get all machines that are in the NEW status. + all_machines = await client.machines.list() + new_machines = [ + machine + for machine in all_machines + if machine.status == NodeStatus.NEW + ] + + # Run commissioning with a custom commissioning script on all new machines. + for machine in new_machines: + machine.commission( + commissioning_scripts=['clear_hardware_raid'], wait=False) + + # Wait until all machines are ready. + failed_machines = [] + completed_machines = [] + while len(new_machines) > 0: + await asyncio.sleep(5) + for machine in list(new_machines): + await machine.refresh() + if machine.status in [ + NodeStatus.COMMISSIONING, NodeStatus.TESTING]: + # Machine is still commissioning or testing. + continue + elif machine.status == NodeStatus.READY: + # Machine is complete. + completed_machines.append(machine) + new_machines.remove(machine) + else: + # Machine has failed commissioning. + failed_machines.append(machine) + new_machines.remove(machine) + + # Print message if any machines failed to commission. + if len(failed_machines) > 0: + for machine in failed_machines: + print("%s: transitioned to unexpected status - %s" % ( + machine.hostname, machine.status_name)) + else: + print("Successfully commissioned %d machines." % len( + completed_machines)) + + +commission_all_machines() +``` + +## Allocating and deploying + +```pycon +>>> help(client.machines.allocate) +Help on method allocate in module maas.client.viscera.machines: + +allocate( + *, hostname:str=None, architecture:str=None, cpus:int=None, + memory:float=None, tags:typing.Sequence=None) + method of maas.client.viscera.machines.MachinesType instance + Allocate a machine. + + :param hostname: The hostname to match. + :param architecture: The architecture to match, e.g. "amd64". + :param cpus: The minimum number of CPUs to match. + :param memory: The minimum amount of RAM to match. + :param tags: The tags to match, as a sequence. Each tag may be + prefixed with a hyphen to denote that the given tag should NOT be + associated with a matched machine. +>>> machine = client.machines.allocate(tags=("foo", "-bar")) +>>> print(machine.status) +NodeStatus.COMMISSIONING +>>> machine.deploy() +>>> print(machine.status) +NodeStatus.DEPLOYING +``` + +## Abort + +If an action is performed on a machine and it needs to be aborted before it +finishes ``abort`` can be used. + +```pycon +>>> machine.commission(wait=False) +>>> machine.status +NodeStatus.COMMISSIONING +>>> machine.abort() +>>> machine.status +NodeStatus.NEW +``` + +## Rescue mode + +Boot the machine into rescue mode and then exit. + +```pycon +>>> machine.enter_rescue_mode() +>>> machine.exit_rescue_mode() +``` + +## Broken & Fixed + +When a machine is identified as broken you can easily mark it broken and then +fixed once the issue is resolved. + +```pycon +>>> machine.mark_broken() +>>> machine.status +NodeStatus.BROKEN +>>> machine.mark_fixed() +>>> machine.status +NodeStatus.READY +``` + +## Owner Data + +Owner data is extra information that you can set on a machine to hold some state information. + +**Note:** Once the machine is no longer in your control the information will be lost. + +```pycon +>>> machine.owner_data +{} +>>> machine.owner_data['state'] = 'my-state-info' +>>> machine.save() +>>> machine.owner_data +{'state': 'my-state-info'} +>>> machine.release() +>>> machine.owner_data +{} +``` + +## Power Control + +The power state of a machine can be controlled outside of deploy, releasing, and rescue mode. If you need to control the power of a BMC independently the `power_on`, `power_off` and `query_power_state` can be of help. + + +```pycon +>>> machine.power_state +PowerState.ON +>>> machine.power_off() +>>> machine.power_state +PowerState.OFF +>>> machine.power_on() +>>> machine.power_state +PowerState.ON +>>> machine.query_power_state() +PowerState.ON +``` + +## Reset Configuration + +It is possible to restore the machine back to exactly how it was after you completed commissioning. This is helpful when you have made a configuration that you no longer want or you want to start fresh. + +```pycon +>>> machine.restore_default_configuration() +>>> # Only restore networking. +>>> machine.restore_networking_configuration() +>>> # Only restore storage configuration. +>>> machine.restore_storage_configuration() +``` diff --git a/doc/viscera/other.md b/doc/client/other.md similarity index 62% rename from doc/viscera/other.md rename to doc/client/other.md index 12c96d55..c4ddc72b 100644 --- a/doc/viscera/other.md +++ b/doc/client/other.md @@ -1,4 +1,8 @@ -# Other objects +

Other objects

+ +There are several other object types available via the client API. Use +``dir()`` and tab-completion to dig around interactively, or read the +code; we've tried to keep it readable. ## Files, users, tags @@ -6,9 +10,9 @@ Similarly to nodes, these sets of objects can be fetched: ```pycon ->>> tags = origin.Tags.read() ->>> files = origin.Files.read() ->>> users = origin.Users.read() +>>> tags = client.tags.list() +>>> files = client.files.list() +>>> users = client.users.list() ``` When reading from collections, as above, the returned object is diff --git a/doc/development/adding-an-object.md b/doc/development/adding-an-object.md new file mode 100644 index 00000000..608c2068 --- /dev/null +++ b/doc/development/adding-an-object.md @@ -0,0 +1,286 @@ +

Adding a new object type

+ +This will show the process by which we can add support for _Space_ +objects, but it should be roughly applicable to other objects. + +---- + + +## Skeleton + +Start by creating a new file in _viscera_. Following the example of +existing objects, name it `maas/client/viscera/spaces.py` (i.e. plural). + +> Why _viscera_? The client we recommend for users is a façade of +> _viscera_, allowing us to present a simplified interface which mingles +> set-like operations with individual ones. This is friendlier to a new +> developer, but _viscera_ itself keeps the two separate for cleanliness +> of implementation. + +Create a skeleton for _Space_ and _Spaces_: + +```python +"""Objects for spaces.""" + +__all__ = [ + "Space", + "Spaces", +] + +from . import ( + Object, + ObjectSet, + ObjectType, +) + + +class SpacesType(ObjectType): + """Metaclass for `Spaces`.""" + + +class Spaces(ObjectSet, metaclass=SpacesType): + """The set of spaces.""" + + +class SpaceType(ObjectType): + """Metaclass for `Space`.""" + + +class Space(Object, metaclass=SpaceType): + """A space.""" +``` + +We create explicit type classes as a place to put class-specific +information and methods. Most interestingly, methods created on the type +classes are _class_ methods on instances of the type. For example: + +```pycon +>>> class FooType(type): +... def hello(cls): +... return "Hello, %s" % cls + +>>> class Foo(metaclass=FooType): +... def goodbye(self): +... return "Goodbye, %s" % self + +>>> Foo.hello() +"Hello, " + +>>> foo = Foo() +>>> foo.goodbye() +'Goodbye, <__main__.Foo object at ...>' +``` + +The difference between using `@classmethod` and this is that those class +methods are not available on instances: + +```pycon + +>>> foo.hello() +Traceback (most recent call last): +... +AttributeError: 'Foo' object has no attribute 'hello' +``` + +This keeps the namespace uncluttered, which is good for interactive, +exploratory development, and it keeps code cleaner too: a class method +**must** be called via the class. + + +## Getting this into the default `Origin` + +In `maas/client/viscera/__init__.py` is the default `Origin` class. This +loads object definitions, like those above, and *binds* them to a +particular server. More about that later, but for now you need to add +`".spaces"` to `Origin.__init__`: + +```diff + ".files", + ".maas", + ".machines", ++ ".spaces", + ".tags", + ".users", + ".version", +``` + + +## Basic accessors + +Add the following basic accessor method to `SpacesType`: + +```python +class SpacesType(ObjectType): + + async def read(cls): + data = await cls._handler.read() + return cls(map(cls._object, data)) +``` + +Let's start working against a real MAAS server: + +```console +$ bin/maas login my-server http://.../MAAS username p4ssw0rd +$ bin/pip install -IU IPython # Don't leave home without it. +$ bin/maas shell --viscera +Welcome to the MAAS shell. + +Predefined objects: + + client: + A pre-canned client for 'madagascar'. + + origin: + A pre-canned `viscera` origin for 'madagascar'. +``` +```pycon +>>> origin.Spaces.read() +, ]> + +>>> origin.Spaces._handler + + +>>> origin.Spaces._origin + +``` + +The `_handler` attribute is the _bones_ handler for spaces. We named the +class "Spaces" and `Origin` paired that up with the _bones_ handler of +the same name. This let us call the lower-level `read()` method. Try +calling it now: + +```pycon +>>> origin.Spaces._handler.read() +[{'id': 0, + 'name': 'space-0', + 'resource_uri': '/MAAS/api/2.0/spaces/0/', + 'subnets': [], + 'vlans': []}, + {'id': -1, + 'name': 'undefined', + 'resource_uri': '/MAAS/api/2.0/spaces/undefined/', + 'subnets': [{'active_discovery': False, + 'allow_proxy': True, + 'cidr': '192.168.1.0/24', + 'dns_servers': [], + 'gateway_ip': '192.168.1.254', + 'id': 1, + 'managed': True, + 'name': '192.168.1.0/24', + 'rdns_mode': 2, + 'resource_uri': '/MAAS/api/2.0/subnets/1/', + 'space': 'undefined', + 'vlan': {'dhcp_on': True, + 'external_dhcp': None, + 'fabric': 'fabric-0', + 'fabric_id': 0, + 'id': 5001, + 'mtu': 1500, + 'name': 'untagged', + 'primary_rack': '4y3h7n', + 'relay_vlan': None, + 'resource_uri': '/MAAS/api/2.0/vlans/5001/', + 'secondary_rack': 'xfaxgw', + 'space': 'undefined', + 'vid': 0}}], + 'vlans': [{'dhcp_on': True, + 'external_dhcp': None, + 'fabric': 'fabric-0', + 'fabric_id': 0, + 'id': 5001, + 'mtu': 1500, + 'name': 'untagged', + 'primary_rack': '4y3h7n', + 'relay_vlan': None, + 'resource_uri': '/MAAS/api/2.0/vlans/5001/', + 'secondary_rack': 'xfaxgw', + 'space': 'undefined', + 'vid': 0}]}] +``` + +Lots of information! + +> By the way, many or most of the IO methods in _python-libmaas_ can be +> called interactively or in a script and they work the same as any +> other synchronous or blocking call. Internally, however, they're all +> asynchronous. They're wrapped in such a way that, when called from +> outside of an _asyncio_ event-loop, they block, but inside they work +> just the same as any other asynchronous call. + +Let's look at those `Space` objects: + +```pycon +>>> space, *_ = origin.Spaces.read() + +>>> dir(space) +[..., '_data', '_handler', '_origin'] + +>>> space._data +{'id': 0, + 'name': 'space-0', + 'resource_uri': '/MAAS/api/2.0/spaces/0/', + 'subnets': [], + 'vlans': []} + +>>> space._handler + + +>>> space._origin is origin +True +``` + +The handler has been associated with this object type like it was for +`Spaces`, so now's a good time to add another accessor method: + +```python +class SpaceType(ObjectType): + + async def read(cls): + data = await cls._handler.read() + return cls(data) +``` + +Try it out: + +```pycon +>>> space = origin.Space.read(0) + +>>> space._data +{'id': 0, + 'name': 'space-0', + 'resource_uri': '/MAAS/api/2.0/spaces/0/', + 'subnets': [], + 'vlans': []} +``` + + +## Getting at the data + +We don't want to work with that `_data` dictionary, we want attributes: + +```python +class Space(Object, metaclass=SpaceType): + """A space.""" + + id = ObjectField.Checked("id", check(int), readonly=True) + name = ObjectField.Checked("name", check(str), readonly=True) +``` + +Try it out in the shell: + +```pycon +>>> space.id, space, name +(0, 'space-0') +``` + + +## Next steps + +That's enough for now, but there's plenty of ground yet to be covered: + +* How to work with the information about subnets and VLANs data that was + returned. + +* How to create, modify, and delete objects. + +* How to test all of this. diff --git a/doc/development/releasing.md b/doc/development/releasing.md new file mode 100644 index 00000000..559f48e3 --- /dev/null +++ b/doc/development/releasing.md @@ -0,0 +1,28 @@ +

Releasing a new version of python-libmaas

+ +1. Clean and test: + + make clean + make test + +1. If you didn't `make clean` just now, do it! Without it the [PyPI][] + uploads may be built incorrectly. + +1. Bump version in ``setup.py``, merge to _master_. + +1. Tag _master_: + + git tag --sign ${version} --message "Release ${version}." + git push origin --tags + +1. Build and push docs to [GitHub][docs]: + + make docs-to-github + +1. Build and push source and wheel to [PyPI][]: + + make upload + + +[docs]: http://maas.github.io/python-libmaas/ +[pypi]: https://pypi.python.org/pypi/python-libmaas diff --git a/doc/index.md b/doc/index.md index e2a2662a..5813d83e 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,41 +1,235 @@ -# Welcome to MAAS's new command-line tool & Python client libraries. +

Welcome to MAAS's new command-line tool & Python client library

-For documentation on the MAAS server components, visit -[maas.ubuntu.com](https://maas.ubuntu.com/docs/). +_python-libmaas_ provides: + +* A command-line tool for working with MAAS servers. + +* A rich and stable Python client library for interacting with MAAS 2.0+ + servers. This can be used in a synchronous/blocking mode, or an + asynchronous/non-blocking mode based on [asyncio][]. + +* A lower-level Python client library, auto-generated to match the MAAS + server it's interacting with. + +For MAAS _server_ documentation, visit +[docs.ubuntu.com](https://docs.ubuntu.com/maas/). + +---- + +This is **ALPHA** software. We are converging on a finished product, but +until we release a beta all APIs could change. + +---- + + +## Installation + +Either work from a branch: + +```console +$ git clone https://github.com/canonical/python-libmaas.git +$ cd python-libmaas +$ make +``` + +Or install with [pip](https://pip.pypa.io/) into a +[virtualenv](https://virtualenv.readthedocs.org/): + +```console +$ virtualenv --python=python3 amc && source amc/bin/activate +$ pip install git+https://github.com/canonical/python-libmaas.git +``` + +Or install from [PyPI](https://pypi.python.org/): + +```console +$ virtualenv --python=python3 amc && source amc/bin/activate +$ pip install python-libmaas +``` + +**Note** that PyPI may lag the others. + +This documentation assumes you're working from a branch or in a +virtualenv. In practice this means it will use partially qualified paths +like ``bin/maas`` instead of bare ``maas`` invocations. If you've +installed from PyPI the ``maas`` command will probably be installed on +your shell's ``PATH`` so you can invoke it as ``maas``. ## Command-line +Best place to start with the CLI is the help menu. + +```console +$ bin/maas help +$ bin/maas help commands +``` + +Once your have familiarized yourself with the available commands you will +want to login to your MAAS. You can either pass arguments to login or it +will ask your for the needed information to login. + +```console +$ bin/maas login +``` + +The CLI supports multiple profiles with ``login``. Use ``profiles`` and +``switch`` to view and change between profiles. + +```console +$ bin/maas profiles +┌─────────┬─────────────────────────────────────┬────────┐ +│ Profile │ URL │ Active │ +├─────────┼─────────────────────────────────────┼────────┤ +│ admin │ http://localhost:5240/MAAS/api/2.0/ │ ✓ │ +│ other │ http://localhost:5240/MAAS/api/2.0/ │ │ +└─────────┴─────────────────────────────────────┴────────┘ +$ bin/maas switch other +$ bin/maas profiles +┌─────────┬─────────────────────────────────────┬────────┐ +│ Profile │ URL │ Active │ +├─────────┼─────────────────────────────────────┼────────┤ +│ admin │ http://localhost:5240/MAAS/api/2.0/ │ │ +│ other │ http://localhost:5240/MAAS/api/2.0/ │ ✓ │ +└─────────┴─────────────────────────────────────┴────────┘ +``` + +The ``nodes``, ``machines``, ``devices``, and ``controllers`` provide access +to either all nodes with ``nodes`` or specific node types with ``machines``, +``devices``, and ``controllers``. + +```console +$ bin/maas nodes +┌────────────────────┬───────────────┐ +│ Hostname │ Type │ +├────────────────────┼───────────────┤ +│ another │ Device │ +│ blake-ubnt-desktop │ Regiond+rackd │ +│ testing │ Device │ +│ win2016 │ Machine │ +└────────────────────┴───────────────┘ +$ bin/maas machines +┌──────────┬───────┬────────┬───────┬───────┬────────┐ +│ Hostname │ Power │ Status │ Arch │ #CPUs │ RAM │ +├──────────┼───────┼────────┼───────┼───────┼────────┤ +│ win2016 │ Off │ Broken │ amd64 │ 4 │ 8.0 GB │ +└──────────┴───────┴────────┴───────┴───────┴────────┘ +$ bin/maas devices +┌──────────┬───────────────┐ +│ Hostname │ IP addresses │ +├──────────┼───────────────┤ +│ another │ 192.168.1.223 │ +│ testing │ 192.168.1.150 │ +│ │ 192.168.1.143 │ +└──────────┴───────────────┘ +$ bin/maas controllers +┌────────────────────┬───────────────┬───────┬───────┬─────────┐ +│ Hostname │ Type │ Arch │ #CPUs │ RAM │ +├────────────────────┼───────────────┼───────┼───────┼─────────┤ +│ blake-ubnt-desktop │ Regiond+rackd │ amd64 │ 8 │ 24.0 GB │ +└────────────────────┴───────────────┴───────┴───────┴─────────┘ +``` + +Tab-completion in ``bash`` and ``tcsh`` is supported too. For example, +in ``bash``: + ```console -$ bin/maas profiles login --help -$ bin/maas profiles login exmpl http://example.com:5240/MAAS/ my_username -Password: … -$ bin/maas list nodes -┌───────────────┬───────────┬───────────────┬───────┬────────┬───────────┬───────┐ -│ Hostname │ System ID │ Architecture │ #CPUs │ RAM │ Status │ Power │ -├───────────────┼───────────┼───────────────┼───────┼────────┼───────────┼───────┤ -│ botswana.maas │ 433334 │ amd64/generic │ 4 │ 8.0 GB │ Ready │ Off │ -│ namibia.maas │ 433333 │ amd64/generic │ 4 │ 8.0 GB │ Allocated │ Off │ -└───────────────┴───────────┴───────────────┴───────┴────────┴───────────┴───────┘ +$ source <(bin/register-python-argcomplete --shell=bash bin/maas) +$ bin/maas +allocate files login nodes shell ... +``` + + +## Client library + +For a developer the simplest entry points into ``python-libmaas`` are +the ``connect`` and ``login`` functions in ``maas.client``. The former +connects to a MAAS server using a previously obtained API key, and the +latter logs-in to MAAS with your username and password. These returns a +``Client`` object that has convenient attributes for working with MAAS. + +For example, this prints out all interfaces on all machines: + +```python +from maas.client import login +client = login( + "http://localhost:5240/MAAS/", + username="my_user", password="my_pass", +) +tmpl = "{0.hostname} {1.name} {1.mac_address}" +for machine in client.machines.list(): + for interface in machine.interfaces: + print(tmpl.format(machine, interface)) ``` +Learn more about the [client](client/index.md). + + +## Shell + +There's an interactive shell. If a profile name is given or a default +profile has been set — see ``maas profiles --help`` — this places a +``Client`` instance in the default namespace (as ``client``) that you +can use interactively or in a script. -## Client libraries +For the best experience install [IPython](https://ipython.org/) first. -There are two client libraries that make use of MAAS's Web API: +```console +$ bin/maas shell +Welcome to the MAAS shell. +... +``` + +```pycon +>>> origin.Version.read() + +>>> dir(client) +[..., 'account', 'boot_resources', ...] +``` + +Scripts can also be run. For example, given the following ``script.py``: + +```python +print("Machines:", len(client.machines.list())) +print("Devices:", len(client.devices.list())) +print("Racks:", len(client.rack_controllers.list())) +print("Regions:", len(client.region_controllers.list())) +``` + +the following will run it against the default profile: + +```console +$ bin/maas shell script.py +Machines: 1 +Devices: 0 +Racks: 2 +Regions: 1 +``` + + +## Development + +It's easy to start hacking on _python-libmaas_: + +```console +$ git clone git@github.com:maas/python-libmaas.git +$ cd python-libmaas +$ make develop +$ make test +``` + +Installing [IPython][] is generally a good idea too: + +```console +$ bin/pip install -UI IPython +``` -* A lower-level library that closely mirrors MAAS's Web API, referred to - as _bones_. The MAAS server publishes a description of its Web API and - _bones_ provides a convenient mechanism to interact with it. +Pull requests are welcome but authors need to sign the [Canonical +contributor license agreement][CCLA] before those PRs can be merged. -* A higher-level library that's designed for developers, referred to as - _viscera_. MAAS's Web API is sometimes unfriendly or inconsistent, but - _viscera_ presents a saner API, designed for developers rather than - machines. -The implementation of [_viscera_](viscera/index.md) makes use of -[_bones_](bones/index.md). _Viscera_ is the API that should be preferred -for application development. +[asyncio]: https://docs.python.org/3/library/asyncio.html +[CCLA]: https://www.ubuntu.com/legal/contributors -Try this next: [Get started with _viscera_](viscera/getting-started.md) +[IPython]: https://ipython.org/ diff --git a/doc/viscera/events.md b/doc/viscera/events.md deleted file mode 100644 index e7e8c354..00000000 --- a/doc/viscera/events.md +++ /dev/null @@ -1,33 +0,0 @@ -# Events - -Events are similar... but different. The only way to get events is by -the ``query`` method: - -```pycon ->>> events = origin.Events.query() -``` - -This accepts a plethora of optional arguments to narrow down the results: - -```pycon ->>> events = origin.Events.query(hostnames={"foo", "bar"}) ->>> events = origin.Events.query(domains={"example.com", "maas.io"}) ->>> events = origin.Events.query(zones=["red", "blue"]) ->>> events = origin.Events.query(macs=("12:34:56:78:90:ab", )) ->>> events = origin.Events.query(system_ids=…) ->>> events = origin.Events.query(agent_name=…) ->>> events = origin.Events.query(level=…) ->>> events = origin.Events.query(after=…, limit=…) -``` - -These arguments can be combined to narrow the results even further. - -The ``level`` argument is a little special. It's a choice from a -predefined set. For convenience, those choices are defined in the -``Level`` enum: - -```pycon ->>> events = origin.Events.query(level=origin.Events.Level.ERROR) -``` - -but you can also pass in the string "ERROR" or the number 40. diff --git a/doc/viscera/getting-started.md b/doc/viscera/getting-started.md deleted file mode 100644 index 8a588b2f..00000000 --- a/doc/viscera/getting-started.md +++ /dev/null @@ -1,107 +0,0 @@ -# Getting started with _viscera_ - - -## Installation - -Either work from a branch: - -```console -$ git clone https://github.com/maas/python-libmaas.git -$ cd python-libmaas -$ make -``` - -Or install with [pip](https://pip.pypa.io/) into a -[virtualenv](https://virtualenv.readthedocs.org/): - -```console -$ virtualenv --python=python3.5 amc && source amc/bin/activate -$ pip install git+https://github.com/maas/python-libmaas.git -``` - -Or install from [PyPI](https://pypi.python.org/): - -```console -$ virtualenv --python=python3.5 amc && source amc/bin/activate -$ pip install python-libmaas -``` - -*Note* that PyPI may lag the others. - - -## Logging-in - -Log-in using the command-line tool and start an interactive Python -shell: - -```console -$ maas profiles login foo http://example.com:5240/MAAS/ admin -Password: … -$ maas shell -``` - -This will provide you with a pre-prepared `origin` object that points to -`foo` from above. This is the root object of the API. - -You can also log-in programmatically: - -```pycon ->>> profile, origin = Origin.login( -... "http://example.com:5240/MAAS/", username="admin", -... password="…") -``` - -The `profile` has not been saved, but it's easy to do so: - -```pycon ->>> profile = profile.replace(name="foo") ->>> with ProfileStore.open() as store: -... store.save(profile) -... store.default = profile -``` - -This does the same as the `maas profiles login` command. - -But there's no need! There's a command built in to do it for you: - -```console -$ bin/maas shell -Welcome to the MAAS shell. - -Predefined variables: - - origin: A `viscera` origin, configured for foo. - session: A `bones` session, configured for foo. - ->>> -``` - - -## Logging-out - -Log-out using the command-line tool: - -```console -$ bin/maas profiles remove foo -``` - -or, programmatically: - -```pycon ->>> with ProfileStore.open() as store: -... store.delete("foo") -``` - - -## `dir()`, `help()`, and tab-completion - -The _viscera_ API has been designed to be very discoverable using -tab-completion, `dir()`, `help()`, and so on. Start with that: - -```pycon ->>> origin. -… -``` - -This works best when you've got [IPython](https://ipython.org/) -installed. diff --git a/doc/viscera/index.md b/doc/viscera/index.md deleted file mode 100644 index feff5044..00000000 --- a/doc/viscera/index.md +++ /dev/null @@ -1,29 +0,0 @@ -# _Viscera_: High-level Python client API - - -## Some example code - -```python -#!/usr/bin/env python3.5 - -from pprint import pprint - -from maas.client import viscera - - -profile, origin = viscera.Origin.login( - "http://localhost:5240/MAAS/", username="alice", - password="wonderland") - -# List all the tags. -print(">>> origin.Tags.read()") -pprint(origin.Tags.read()) -print(">>> Or: list(origin.Tags)") -pprint(list(origin.Tags)) - -# List all the nodes. -print(">>> origin.Nodes.read()") -pprint(origin.Nodes.read()) -print(">>> Or: list(origin.Nodes)") -pprint(list(origin.Nodes)) -``` diff --git a/doc/viscera/nodes.md b/doc/viscera/nodes.md deleted file mode 100644 index 94f90aff..00000000 --- a/doc/viscera/nodes.md +++ /dev/null @@ -1,55 +0,0 @@ -# _Viscera_: Working with nodes - - -## Listing - -```pycon ->>> for node in origin.Nodes: -... print(repr(node)) - - -``` - -Individual nodes can be read from the Web API. - -```pycon ->>> node = origin.Node.read(system_id="433333") -``` - -Nodes have many useful attributes: - -```pycon ->>> node.architecture -'amd64/generic' ->>> node.cpus -4 -``` - -Don't forget to try using tab-completion — the objects have been -designed to be particularly friendly for interactive use — or -``dir(node)`` to find out what other fields and methods are available. - -__TODO__: Updating nodes. - - -## Acquiring and starting - -```pycon ->>> help(origin.Nodes.acquire) -acquire(*, hostname:str=None, architecture:str=None, cpus:int=None, - memory:float=None, tags:typing.Sequence=None) method of - maas.client.viscera.NodesType instance - :param hostname: The hostname to match. - :param architecture: The architecture to match, e.g. "amd64". - :param cpus: The minimum number of CPUs to match. - :param memory: The minimum amount of RAM to match. - :param tags: The tags to match, as a sequence. Each tag may be - prefixed with a hyphen to denote that the given tag should NOT be - associated with a matched node. ->>> node = origin.Nodes.acquire(tags=("foo", "-bar")) ->>> print(node.status_name) -Acquired ->>> node.start() ->>> print(node.status_name) -Deploying -``` diff --git a/integrate/__init__.py b/integrate/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/integrate/__main__.py b/integrate/__main__.py new file mode 100644 index 00000000..a386448e --- /dev/null +++ b/integrate/__main__.py @@ -0,0 +1,7 @@ +import sys + +import testtools.run + + +argv = sys.argv[0], "discover", "integrate", *sys.argv[1:] +testtools.run.main(argv, sys.stdout) diff --git a/integrate/test.py b/integrate/test.py new file mode 100644 index 00000000..13d57b4d --- /dev/null +++ b/integrate/test.py @@ -0,0 +1,311 @@ +"""Integration tests for `maas.client`.""" + +from collections import Mapping +from datetime import datetime +from http import HTTPStatus +import io +from itertools import repeat +import random +from time import sleep + +from maas.client import ( + bones, + viscera, +) +from maas.client.testing import ( + make_name_without_spaces, + TestCase, +) +from maas.client.utils import ( + creds, + profiles, + retries, +) +from testtools.matchers import ( + AllMatch, + Equals, + Is, + IsInstance, + MatchesAll, + MatchesAny, + MatchesStructure, +) + + +kiB = 2 ** 10 +MiB = 2 ** 20 + + +def scenarios(): + with profiles.ProfileStore.open() as config: + return tuple( + (profile.name, dict(profile=profile)) + for profile in map(config.load, config) + ) + + +class IntegrationTestCase(TestCase): + + scenarios = scenarios() + + def setUp(self): + super(IntegrationTestCase, self).setUp() + self.session = bones.SessionAPI.fromProfile(self.profile) + self.origin = viscera.Origin(self.session) + + +class TestAccount(IntegrationTestCase): + + def test__create_and_delete_credentials(self): + credentials = self.origin.Account.create_credentials() + self.assertThat(credentials, IsInstance(creds.Credentials)) + self.origin.Account.delete_credentials(credentials) + + +class TestBootResources(IntegrationTestCase): + + def test__list_boot_resources(self): + boot_resources = self.origin.BootResources.read() + self.assertThat(boot_resources, MatchesAll( + IsInstance(self.origin.BootResources), + AllMatch(IsInstance(self.origin.BootResource)), + )) + self.assertThat( + boot_resources, + AllMatch(MatchesStructure( + id=IsInstance(int), + type=IsInstance(str), + name=IsInstance(str), + architecture=IsInstance(str), + subarches=Optional(IsInstance(str)), + sets=Optional(IsInstance(Mapping)), + )), + ) + + def test__create_and_delete_boot_resource(self): + chunk = random.getrandbits(8 * 128).to_bytes(128, "big") + content = b"".join(repeat(chunk, 5 * MiB // len(chunk))) + boot_resource = self.origin.BootResources.create( + make_name_without_spaces("ubuntu", "/"), "amd64/generic", + io.BytesIO(content)) + self.assertThat(boot_resource, IsInstance(self.origin.BootResource)) + boot_resource.delete() + error = self.assertRaises( + bones.CallError, self.origin.BootResource.read, boot_resource.id) + self.assertThat(error, MatchesStructure( + status=Equals(HTTPStatus.NOT_FOUND))) + + +class TestBootSources(IntegrationTestCase): + + def test__create_and_delete_source_with_keyring_filename(self): + source_url = make_name_without_spaces("http://maas.example.com/") + keyring_filename = make_name_without_spaces("keyring-filename") + boot_source = self.origin.BootSources.create( + source_url, keyring_filename=keyring_filename) + self.assertThat(boot_source, IsInstance(self.origin.BootSource)) + boot_source.delete() + error = self.assertRaises( + bones.CallError, self.origin.BootSource.read, boot_source.id) + self.assertThat(error, MatchesStructure( + status=Equals(HTTPStatus.NOT_FOUND))) + + def test__create_and_delete_source_with_keyring_data(self): + source_url = make_name_without_spaces("http://maas.example.com/") + keyring_data = make_name_without_spaces("keyring-data").encode() + boot_source = self.origin.BootSources.create( + source_url, keyring_data=io.BytesIO(keyring_data)) + self.assertThat(boot_source, IsInstance(self.origin.BootSource)) + boot_source.delete() + error = self.assertRaises( + bones.CallError, self.origin.BootSource.read, boot_source.id) + self.assertThat(error, MatchesStructure( + status=Equals(HTTPStatus.NOT_FOUND))) + + def test__list_boot_sources(self): + boot_sources = self.origin.BootSources.read() + self.assertThat(boot_sources, MatchesAll( + IsInstance(self.origin.BootSources), + AllMatch(IsInstance(self.origin.BootSource)), + )) + self.assertThat( + boot_sources, + AllMatch(MatchesStructure( + id=IsInstance(int), + url=IsInstance(str), + keyring_filename=IsInstance(str), + keyring_data=IsInstance(str), # ??? Binary, no? + created=IsInstance(datetime), + updated=IsInstance(datetime), + )), + ) + + +# TestBootSourceSelections +# TestDevices + + +class TestEvents(IntegrationTestCase): + + def test__query_events(self): + events = self.origin.Events.query() + self.assertThat(events, IsInstance(self.origin.Events)) + events = events.prev() + self.assertThat(events, IsInstance(self.origin.Events)) + events = events.next() + self.assertThat(events, IsInstance(self.origin.Events)) + + def test__events(self): + self.assertThat( + self.origin.Events.query(), + AllMatch(MatchesStructure( + event_id=IsInstance(int), + event_type=IsInstance(str), + system_id=IsInstance(str), + hostname=IsInstance(str), + level=IsInstance(viscera.events.Level), + created=IsInstance(datetime), + description=IsInstance(str), + )), + ) + + +# TestFiles +# TestMAAS + + +class TestMachines(IntegrationTestCase): + + def test__list_machines(self): + machines = self.origin.Machines.read() + self.assertThat(machines, MatchesAll( + IsInstance(self.origin.Machines), + AllMatch(IsInstance(self.origin.Machine)), + )) + self.assertThat( + machines, + AllMatch(MatchesStructure( + # This is NOT exhaustive. + system_id=IsInstance(str), + architecture=IsInstance(str), + hostname=IsInstance(str), + ip_addresses=IsInstance(list), + status=IsInstance(int), + status_name=IsInstance(str), + tags=IsInstance(list), + )), + ) + + def XXXtest__allocate_deploy_and_release(self): + machines_ready = [ + machine for machine in self.origin.Machines.read() + if machine.status_name == "Ready" + ] + if len(machines_ready) == 0: + self.skip("No machines available.") + + # Allocate one of the ready machines. XXX: This ought to be a method + # on Machine or take a `system_id` argument. + machine = random.choice(machines_ready) + machine = self.origin.Machines.allocate(hostname=machine.hostname) + self.assertThat(machine.status_name, Equals("Allocated")) + + try: + # Deploy the machine with defaults. + machine = machine.deploy() + self.assertThat(machine.status_name, Equals("Deploying")) + # Wait for the machine to deploy. + for elapsed, remaining, wait in retries(600, 10): + machine = self.origin.Machine.read(machine.system_id) + if machine.status_name == "Deploying": + sleep(wait) + else: + break + else: + self.fail("Timed-out waiting for machine to deploy.") + # The machine has deployed. + self.assertThat(machine.status_name, Equals("Deployed")) + + finally: + # Release the machine. + machine = machine.release("Finished with this now, thanks.") + self.assertThat(machine.status_name, Equals("Releasing")) + # Wait for the machine to release. + for elapsed, remaining, wait in retries(300, 10): + machine = self.origin.Machine.read(machine.system_id) + if machine.status_name == "Releasing": + sleep(wait) + else: + break + else: + self.fail("Timed-out waiting for machine to release.") + # The machine has been released. + self.assertThat(machine.status_name, Equals("Ready")) + + +class TestRackControllers(IntegrationTestCase): + + def test__list_rack_controllers(self): + machines = self.origin.RackControllers.read() + self.assertThat(machines, MatchesAll( + IsInstance(self.origin.RackControllers), + AllMatch(IsInstance(self.origin.RackController)), + )) + self.assertThat( + machines, + AllMatch(MatchesStructure( + # This is NOT exhaustive. + architecture=IsInstance(str), + cpus=IsInstance(int), + distro_series=IsInstance(str), + fqdn=IsInstance(str), + hostname=IsInstance(str), + ip_addresses=IsInstance(list), + memory=IsInstance(int), + power_state=IsInstance(str), + system_id=IsInstance(str), + zone=IsInstance(self.origin.Zone), + )), + ) + + +class TestRegionControllers(IntegrationTestCase): + + def test__list_region_controllers(self): + machines = self.origin.RegionControllers.read() + self.assertThat(machines, MatchesAll( + IsInstance(self.origin.RegionControllers), + AllMatch(IsInstance(self.origin.RegionController)), + )) + self.assertThat( + machines, + AllMatch(MatchesStructure( + # This is NOT exhaustive. + architecture=IsInstance(str), + cpus=IsInstance(int), + distro_series=IsInstance(str), + fqdn=IsInstance(str), + hostname=IsInstance(str), + ip_addresses=IsInstance(list), + memory=IsInstance(int), + power_state=IsInstance(str), + system_id=IsInstance(str), + zone=IsInstance(self.origin.Zone), + )), + ) + + +# TestTags +# TestTesting +# TestUsers +# TestVersion +# TestZones + + +# Additional matchers. + +def Optional(matcher, default=Is(None)): + return MatchesAny(matcher, default) + + +# End. diff --git a/maas/__init__.py b/maas/__init__.py index ece379ce..5284146e 100644 --- a/maas/__init__.py +++ b/maas/__init__.py @@ -1,2 +1 @@ -import pkg_resources -pkg_resources.declare_namespace(__name__) +__import__("pkg_resources").declare_namespace(__name__) diff --git a/maas/client/__init__.py b/maas/client/__init__.py index 55532e15..874a8230 100644 --- a/maas/client/__init__.py +++ b/maas/client/__init__.py @@ -1,9 +1,12 @@ """Basic entry points.""" -from . import _client +__all__ = ["connect", "login"] +from .utils.maas_async import asynchronous -def connect(url, *, apikey=None, insecure=False): + +@asynchronous +async def connect(url, *, apikey=None, insecure=False): """Connect to MAAS at `url` using a previously obtained API key. :param url: The URL of MAAS, e.g. http://maas.example.com:5240/MAAS/ @@ -13,13 +16,15 @@ def connect(url, *, apikey=None, insecure=False): :return: A client object. """ + from .facade import Client # Lazy. from .viscera import Origin # Lazy. - profile, origin = Origin.connect( - url, apikey=apikey, insecure=insecure) - return _client.Client(origin) + + profile, origin = await Origin.connect(url, apikey=apikey, insecure=insecure) + return Client(origin) -def login(url, *, username=None, password=None, insecure=False): +@asynchronous +async def login(url, *, username=None, password=None, insecure=False): """Connect to MAAS at `url` with a user name and password. :param url: The URL of MAAS, e.g. http://maas.example.com:5240/MAAS/ @@ -29,7 +34,10 @@ def login(url, *, username=None, password=None, insecure=False): :return: A client object. """ + from .facade import Client # Lazy. from .viscera import Origin # Lazy. - profile, origin = Origin.login( - url, username=username, password=password, insecure=insecure) - return _client.Client(origin) + + profile, origin = await Origin.login( + url, username=username, password=password, insecure=insecure + ) + return Client(origin) diff --git a/maas/client/_client.py b/maas/client/_client.py deleted file mode 100644 index 8b84340e..00000000 --- a/maas/client/_client.py +++ /dev/null @@ -1,86 +0,0 @@ -"""Client facade.""" - -from functools import update_wrapper - - -class Facade: - """Present a simplified API for interacting with MAAS. - - The viscera API separates set-based interactions from those on individual - objects — e.g. Machines and Machine — which mirrors the way MAAS's API is - actually constructed, helps to avoid namespace clashes, and makes testing - cleaner. - - However, we want to present a simplified commingled namespace to users of - MAAS's *client* API. For example, all entry points related to machines - should be available as ``client.machines``. This facade class allows us to - present that commingled namespace without coding it as such. - """ - - def __init__(self, client, name, methods): - super(Facade, self).__init__() - self._client = client - self._name = name - self._populate(methods) - - def _populate(self, methods): - for name, func in methods.items(): - setattr(self, name, func) - - def __repr__(self): - return "<%s>" % self._name - - -class FacadeDescriptor: - """Lazily create a facade on first use. - - It will be stored in the instance dictionary using the given name. This - should match the name by which the descriptor is bound into the instance - class's namespace: as this is a non-data descriptor [1] this will yield - create-on-first-use behaviour. - - The factory function should accept a single argument, an `Origin`, and - return a dict mapping method names to methods of objects obtained from the - origin. - - [1] https://docs.python.org/3.5/howto/descriptor.html#descriptor-protocol - """ - - def __init__(self, name, factory): - super(FacadeDescriptor, self).__init__() - self.name, self.factory = name, factory - - def __get__(self, obj, typ=None): - methods = self.factory(obj._origin) - facade = Facade(obj, self.name, methods) - obj.__dict__[self.name] = facade - return facade - - -def facade(factory): - """Declare a method as a facade factory.""" - wrapper = FacadeDescriptor(factory.__name__, factory) - return update_wrapper(wrapper, factory) - - -class Client: - """A simplified API for interacting with MAAS.""" - - def __init__(self, origin): - super(Client, self).__init__() - self._origin = origin - - @facade - def machines(origin): - return { - "allocate": origin.Machines.allocate, - "get": origin.Machine.read, - "list": origin.Machines.read, - } - - @facade - def devices(origin): - return { - "get": origin.Device.read, - "list": origin.Devices.read, - } diff --git a/maas/client/bones/__init__.py b/maas/client/bones/__init__.py index defc5b6c..7b5b8d31 100644 --- a/maas/client/bones/__init__.py +++ b/maas/client/bones/__init__.py @@ -4,27 +4,21 @@ hence the name "bones". """ -__all__ = [ - "CallError", - "SessionAPI", -] - -from collections import ( - Iterable, - namedtuple, -) -from http import HTTPStatus +__all__ = ["CallError", "SessionAPI"] + +import typing + +from collections import namedtuple +from collections.abc import Iterable import json -import re -from urllib.parse import urljoin +from urllib.parse import urlparse import aiohttp -import aiohttp.errors +from . import helpers from .. import utils from ..utils import profiles -from ..utils.connect import connect -from ..utils.login import login +from ..utils.maas_async import asynchronous class SessionError(Exception): @@ -35,26 +29,19 @@ class SessionAPI: """Represents an API session with a remote MAAS installation.""" @classmethod - async def fromURL( - cls, url, *, credentials=None, insecure=False): + @asynchronous + async def fromURL(cls, url, *, credentials=None, insecure=False): """Return a `SessionAPI` for a given MAAS instance.""" - url_describe = urljoin(url, "describe/") - connector = aiohttp.TCPConnector(verify_ssl=(not insecure)) - session = aiohttp.ClientSession(connector=connector) - async with session, session.get(url_describe) as response: - if response.status != HTTPStatus.OK: - raise SessionError( - "{0} -> {1.status} {1.reason}".format( - url, response)) - elif response.content_type != "application/json": - raise SessionError( - "Expected application/json, got: %s" - % response.content_type) - else: - description = await response.json() - session = cls(description, credentials) - session.insecure = insecure - return session + try: + description = await helpers.fetch_api_description(url, insecure=insecure) + except helpers.RemoteError as error: + # For now just re-raise as SessionError. + raise SessionError(str(error)) + else: + session = cls(url, description, credentials) + session.scheme = urlparse(url).scheme + session.insecure = insecure + return session @classmethod def fromProfile(cls, profile): @@ -62,7 +49,10 @@ def fromProfile(cls, profile): :see: `ProfileStore`. """ - return cls(profile.description, profile.credentials) + session = cls(profile.url, profile.description, profile.credentials) + session.scheme = urlparse(profile.url).scheme + session.insecure = profile.other.get("insecure", False) + return session @classmethod def fromProfileName(cls, name): @@ -74,46 +64,51 @@ def fromProfileName(cls, name): return cls.fromProfile(config.load(name)) @classmethod - def login( - cls, url, *, username=None, password=None, insecure=False): + @asynchronous + async def login(cls, url, *, username=None, password=None, insecure=False): """Make a `SessionAPI` by logging-in with a username and password. :return: A tuple of ``profile`` and ``session``, where the former is an unsaved `Profile` instance, and the latter is a `SessionAPI` instance made using the profile. """ - profile = login( - url=url, username=username, password=password, insecure=insecure) - session = cls(profile.description, profile.credentials) + profile = await helpers.login( + url=url, username=username, password=password, insecure=insecure + ) + session = cls(url, profile.description, profile.credentials) + session.scheme = urlparse(url).scheme session.insecure = insecure return profile, session @classmethod - def connect( - cls, url, *, apikey=None, insecure=False): + @asynchronous + async def connect(cls, url, *, apikey=None, insecure=False): """Make a `SessionAPI` by connecting with an apikey. :return: A tuple of ``profile`` and ``session``, where the former is an unsaved `Profile` instance, and the latter is a `SessionAPI` instance made using the profile. """ - profile = connect( - url=url, apikey=apikey, insecure=insecure) - session = cls(profile.description, profile.credentials) + profile = await helpers.connect(url=url, apikey=apikey, insecure=insecure) + session = cls(url, profile.description, profile.credentials) + session.scheme = urlparse(url).scheme session.insecure = insecure return profile, session # Set these on instances. + scheme = "http" insecure = False debug = False - def __init__(self, description, credentials=None): + def __init__(self, url, description, credentials=None): """Construct a `SessionAPI`. + :param url: MAAS URL :param description: The description of the remote API. See `fromURL`. :param credentials: Credentials for the remote system. Optional. """ super(SessionAPI, self).__init__() + self.__url = url self.__description = description self.__credentials = credentials self.__populate() @@ -123,15 +118,15 @@ def __populate(self): if self.__credentials is None: for resource in resources: if resource["anon"] is not None: - handler = HandlerAPI(resource["anon"], resource, self) + handler = HandlerAPI(self.__url, resource["anon"], resource, self) setattr(self, handler.name, handler) else: for resource in resources: if resource["auth"] is not None: - handler = HandlerAPI(resource["auth"], resource, self) + handler = HandlerAPI(self.__url, resource["auth"], resource, self) setattr(self, handler.name, handler) elif resource["anon"] is not None: - handler = HandlerAPI(resource["anon"], resource, self) + handler = HandlerAPI(self.__url, resource["anon"], resource, self) setattr(self, handler.name, handler) @property @@ -161,9 +156,10 @@ class HandlerAPI: operations. """ - def __init__(self, handler, resource, session): + def __init__(self, url, handler, resource, session): """Construct a `HandlerAPI`. + :param url: MAAS URL :param handler: The handler description from the overall API description document. See `SessionAPI`. :param resource: The parent of `handler` in the API description @@ -171,6 +167,7 @@ def __init__(self, handler, resource, session): :param session: The `SessionAPI`. """ super(HandlerAPI, self).__init__() + self.__url = url self.__handler = handler self.__resource = resource self.__session = session @@ -185,12 +182,7 @@ def __populate(self): @property def name(self): """A stable, human-readable name and identifier for this handler.""" - name = self.__handler["name"] - if name.startswith("Anon"): - name = name[4:] - if name.endswith("Handler"): - name = name[:-7] - return re.sub('maas', 'MAAS', name, flags=re.IGNORECASE) + return helpers.derive_resource_name(self.__handler["name"]) @property def uri(self): @@ -199,7 +191,8 @@ def uri(self): This will typically contain replacement patterns; these are interpolated in `CallAPI`. """ - return self.__handler["uri"] + url = urlparse(self.__url) + return f"{url.scheme}://{url.netloc}{self.__handler['path']}" @property def params(self): @@ -222,7 +215,8 @@ def session(self): @property def actions(self): return [ - (name, value) for name, value in vars(self).items() + (name, value) + for name, value in vars(self).items() if not name.startswith("_") and isinstance(value, ActionAPI) ] @@ -291,6 +285,7 @@ def bind(self, **params): """ return CallAPI(params, self) + @asynchronous async def __call__(self, **data): """Convenience method to do ``this.bind(**params).call(**data).data``. @@ -298,36 +293,54 @@ async def __call__(self, **data): Whatever remains is assumed to be data to be passed to ``call()`` as keyword arguments. + All keys in ``params`` that are prefixed with '_' are remapped without + the '_' prefix into the ``call()``. This is used when the ``params`` + and data passed to the call have the same key. + :raise KeyError: If not all required arguments are provided. See `CallAPI.call()` for return information and exceptions. """ + data = dict(data) params = {name: data.pop(name) for name in self.handler.params} + for key, value in data.copy().items(): + if isinstance(value, typing.Mapping): + del data[key] + for nested_key, nested_value in value.items(): + data[key + "_" + nested_key] = nested_value + for key, value in data.copy().items(): + if key.startswith("_"): + data[key[1:]] = data.pop(key) response = await self.bind(**params).call(**data) return response.data def __repr__(self): if self.op is None: - return "" % ( - self.fullname, self.method, self.handler.uri) + return "" % (self.fullname, self.method, self.handler.uri) else: return "" % ( - self.fullname, self.method, self.handler.uri, self.op) + self.fullname, + self.method, + self.handler.uri, + self.op, + ) CallResult = namedtuple("CallResult", ("response", "content", "data")) class CallError(Exception): - def __init__(self, request, response, content, call): desc_for_request = "%(method)s %(uri)s" % request desc_for_response = "HTTP %s %s" % (response.status, response.reason) desc_for_content = content.decode("utf-8", "replace") desc = "%s -> %s (%s)" % ( - desc_for_request, desc_for_response, - desc_for_content if len(desc_for_content) <= 50 else ( - desc_for_content[:49] + "…")) + desc_for_request, + desc_for_response, + desc_for_content + if len(desc_for_content) <= 50 + else (desc_for_content[:49] + "…"), + ) super(CallError, self).__init__(desc) self.request = request self.response = response @@ -336,11 +349,10 @@ def __init__(self, request, response, content, call): @property def status(self): - return int(self.response["status"]) + return self.response.status class CallAPI: - def __init__(self, params, action): """Create a new `CallAPI`. @@ -360,9 +372,10 @@ def __validate(self): raise TypeError("%s takes no arguments" % self.action.fullname) else: params_expected_desc = ", ".join(sorted(params_expected)) - raise TypeError("%s takes %d arguments: %s" % ( - self.action.fullname, len(params_expected), - params_expected_desc)) + raise TypeError( + "%s takes %d arguments: %s" + % (self.action.fullname, len(params_expected), params_expected_desc) + ) @property def action(self): @@ -375,7 +388,10 @@ def uri(self): # TODO: this is el-cheapo URI Template # support; use uritemplate-py # here? - return self.action.handler.uri.format(**self.__params) + uri = urlparse(self.action.handler.uri) + if uri.scheme != self.action.handler.session.scheme: + uri = uri._replace(scheme=self.action.handler.session.scheme) + return uri.geturl().format(**self.__params) def rebind(self, **params): """Rebind the parameters into the URI. @@ -403,9 +419,10 @@ def prepare(self, data): :param data: Data to pass in the *body* of the request. :type data: dict """ + def expand(data): for name, value in data.items(): - if isinstance(value, Iterable): + if isinstance(value, Iterable) and not isinstance(value, str): for value in value: yield name, value else: @@ -421,7 +438,8 @@ def expand(data): # Bundle things up ready to throw over the wire. uri, body, headers = utils.prepare_payload( - self.action.op, self.action.method, self.uri, data) + self.action.op, self.action.method, self.uri, data + ) # Headers are returned as a list, but they must be a dict for # the signing machinery. @@ -434,6 +452,7 @@ def expand(data): return uri, body, headers + @asynchronous async def dispatch(self, uri, body, headers): """Dispatch the call via HTTP. @@ -445,8 +464,8 @@ async def dispatch(self, uri, body, headers): session = aiohttp.ClientSession(connector=connector) async with session: response = await session.request( - self.action.method, uri, data=body, - headers=_prefer_json(headers)) + self.action.method, uri, data=body, headers=_prefer_json(headers) + ) async with response: # Fetch the raw body content. content = await response.read() @@ -468,14 +487,14 @@ async def dispatch(self, uri, body, headers): # Decode from JSON if that's what it's declared as. if response.content_type is None: data = await response.read() - elif response.content_type.endswith('/json'): + elif response.content_type.endswith("/json"): data = await response.json() else: data = await response.read() if response.content_type is None: data = content - elif response.content_type.endswith('/json'): + elif response.content_type.endswith("/json"): # JSON should always be UTF-8. data = json.loads(content.decode("utf-8")) else: diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py new file mode 100644 index 00000000..a875b995 --- /dev/null +++ b/maas/client/bones/helpers.py @@ -0,0 +1,305 @@ +"""Miscellaneous helpers for Bones.""" + +__all__ = [ + "authenticate", + "connect", + "ConnectError", + "derive_resource_name", + "fetch_api_description", + "login", + "LoginError", + "LoginNotSupported", + "PasswordWithoutUsername", + "RemoteError", + "UsernameWithoutPassword", +] + +import asyncio +from concurrent import futures +from getpass import getuser +from http import HTTPStatus +from socket import gethostname +import typing +from urllib.parse import ParseResult, SplitResult, urljoin, urlparse + +import aiohttp +from macaroonbakery import httpbakery + +from ..utils import api_url +from ..utils.maas_async import asynchronous +from ..utils.creds import Credentials +from ..utils.profiles import Profile + + +class RemoteError(Exception): + """Miscellaneous error related to a remote system.""" + + +async def fetch_api_description( + url: typing.Union[str, ParseResult, SplitResult], insecure: bool = False +): + """Fetch the API description from the remote MAAS instance.""" + url_describe = urljoin(_ensure_url_string(url), "describe/") + connector = aiohttp.TCPConnector(verify_ssl=(not insecure)) + session = aiohttp.ClientSession(connector=connector) + async with session, session.get(url_describe) as response: + if response.status != HTTPStatus.OK: + raise RemoteError("{0} -> {1.status} {1.reason}".format(url, response)) + elif response.content_type != "application/json": + raise RemoteError( + "Expected application/json, got: %s" % response.content_type + ) + else: + return await response.json() + + +def _ensure_url_string(url): + """Convert `url` to a string URL if it isn't one already.""" + if isinstance(url, str): + return url + elif isinstance(url, (ParseResult, SplitResult)): + return url.geturl() + else: + raise TypeError("Could not convert %r to a string URL." % (url,)) + + +def derive_resource_name(name): + """A stable, human-readable name and identifier for a resource.""" + if name.startswith("Anon"): + name = name[4:] + if name.endswith("Handler"): + name = name[:-7] + if name == "Maas": + name = "MAAS" + return name + + +class ConnectError(Exception): + """An error with connecting.""" + + +@asynchronous +async def connect(url, *, apikey=None, insecure=False): + """Connect to a remote MAAS instance with `apikey`. + + Returns a new :class:`Profile` which has NOT been saved. To connect AND + save a new profile:: + + profile = connect(url, apikey=apikey) + profile = profile.replace(name="mad-hatter") + + with profiles.ProfileStore.open() as config: + config.save(profile) + # Optionally, set it as the default. + config.default = profile.name + + """ + url = api_url(url) + url = urlparse(url) + + if url.username is not None: + raise ConnectError( + "Cannot provide user-name explicitly in URL (%r) when connecting; " + "use login instead." % url.username + ) + if url.password is not None: + raise ConnectError( + "Cannot provide password explicitly in URL (%r) when connecting; " + "use login instead." % url.username + ) + + if apikey is None: + credentials = None # Anonymous access. + else: + credentials = Credentials.parse(apikey) + + description = await fetch_api_description(url, insecure) + + # Return a new (unsaved) profile. + return Profile( + name=url.netloc, + url=url.geturl(), + credentials=credentials, + description=description, + insecure=insecure, + ) + + +class LoginError(Exception): + """An error with logging-in.""" + + +class PasswordWithoutUsername(LoginError): + """A password was provided without a corresponding user-name.""" + + +class UsernameWithoutPassword(LoginError): + """A user-name was provided without a corresponding password.""" + + +class LoginNotSupported(LoginError): + """Server does not support login-type auth for API clients.""" + + +class MacaroonLoginNotSupported(LoginError): + """Server does not support macaroon auth for API clients.""" + + +@asynchronous +async def login(url, *, anonymous=False, username=None, password=None, insecure=False): + """Log-in to a remote MAAS instance. + + Returns a new :class:`Profile` which has NOT been saved. To log-in AND + save a new profile:: + + profile = login(url, username="alice", password="wonderland") + profile = profile.replace(name="mad-hatter") + + with profiles.ProfileStore.open() as config: + config.save(profile) + # Optionally, set it as the default. + config.default = profile.name + + :raise RemoteError: An unexpected error from the remote system. + :raise LoginError: An error related to logging-in. + :raise PasswordWithoutUsername: Password given, but not username. + :raise UsernameWithoutPassword: Username given, but not password. + :raise LoginNotSupported: Server does not support API client log-in. + """ + url = api_url(url) + url = urlparse(url) + + if username is None: + username = url.username + else: + if url.username is None: + pass # Anonymous access. + else: + raise LoginError( + "User-name provided explicitly (%r) and in URL (%r); " + "provide only one." % (username, url.username) + ) + + if password is None: + password = url.password + else: + if url.password is None: + pass # Anonymous access. + else: + raise LoginError( + "Password provided explicitly (%r) and in URL (%r); " + "provide only one." % (password, url.password) + ) + + # Remove user-name and password from the URL. + userinfo, _, hostinfo = url.netloc.rpartition("@") + url = url._replace(netloc=hostinfo) + + if username is None: + if password: + raise PasswordWithoutUsername( + "Password provided without user-name; specify user-name." + ) + elif anonymous: + credentials = None + else: + credentials = await authenticate_with_macaroon( + url.geturl(), insecure=insecure + ) + else: + if password is None: + raise UsernameWithoutPassword( + "User-name provided without password; specify password." + ) + else: + credentials = await authenticate( + url.geturl(), username, password, insecure=insecure + ) + + description = await fetch_api_description(url, insecure) + profile_name = username or url.netloc + + # Return a new (unsaved) profile. + return Profile( + name=profile_name, + url=url.geturl(), + credentials=credentials, + description=description, + insecure=insecure, + ) + + +async def authenticate_with_macaroon(url, insecure=False): + """Login via macaroons and generate and return new API keys.""" + executor = futures.ThreadPoolExecutor(max_workers=1) + + def get_token(): + client = httpbakery.Client() + resp = client.request( + "POST", + "{}/account/?op=create_authorisation_token".format(url), + verify=not insecure, + ) + if resp.status_code == HTTPStatus.UNAUTHORIZED: + # if the auteentication with Candid fails, an exception is raised + # above so we don't get here + raise MacaroonLoginNotSupported("Macaroon authentication not supported") + if resp.status_code != HTTPStatus.OK: + raise LoginError("Login failed: {}".format(resp.text)) + result = resp.json() + return "{consumer_key}:{token_key}:{token_secret}".format(**result) + + loop = asyncio.get_event_loop() + return await loop.run_in_executor(executor, get_token) + + +async def authenticate(url, username, password, *, insecure=False): + """Obtain a new API key by logging into MAAS. + + :param url: URL for the MAAS API (i.e. ends with ``/api/x.y/``). + :param insecure: If true, don't verify SSL/TLS certificates. + :return: A `Credentials` instance. + + :raise RemoteError: An unexpected error from the remote system. + :raise LoginNotSupported: Server does not support API client log-in. + """ + url_versn = urljoin(url, "version/") + url_authn = urljoin(url, "../../accounts/authenticate/") + + def check_response_is_okay(response): + if response.status != HTTPStatus.OK: + raise RemoteError( + "{0} -> {1.status} {1.reason}".format( + response.url_obj.human_repr(), response + ) + ) + + connector = aiohttp.TCPConnector(verify_ssl=(not insecure)) + session = aiohttp.ClientSession(connector=connector) + async with session: + # Check that this server supports `authenticate-api`. + async with session.get(url_versn) as response: + check_response_is_okay(response) + version_info = await response.json() + + if "authenticate-api" not in version_info["capabilities"]: + raise LoginNotSupported( + "Server does not support automated client log-in. " + "Please obtain an API token via the MAAS UI." + ) + + # POST to the `authenticate` endpoint. + data = { + "username": username, + "password": password, + "consumer": "%s@%s" % (getuser(), gethostname()), + } + async with session.post(url_authn, data=data) as response: + check_response_is_okay(response) + token_info = await response.json() + + return Credentials( + token_info["consumer_key"], + token_info["token_key"], + token_info["token_secret"], + ) diff --git a/maas/client/bones/testing/__init__.py b/maas/client/bones/testing/__init__.py new file mode 100644 index 00000000..9577e755 --- /dev/null +++ b/maas/client/bones/testing/__init__.py @@ -0,0 +1,100 @@ +"""Testing helpers for the Bones API.""" + +__all__ = ["api_descriptions", "DescriptionServer", "list_api_descriptions"] + +import http +import http.server +import json +from operator import itemgetter +from pathlib import Path +import re +import threading + +import fixtures +from pkg_resources import resource_filename, resource_listdir + + +def list_api_descriptions(): + """List API description documents. + + They're searched for in the same directory as this file, and their name + must match "apiXX.json" where "XX" denotes the major and minor version + number of the API. + """ + for filename in resource_listdir(__name__, "."): + match = re.match(r"api(\d)(\d)[.]json", filename) + if match is not None: + version = tuple(map(int, match.groups())) + path = resource_filename(__name__, filename) + name = "%d.%d" % version + yield name, version, Path(path) + + +def load_api_descriptions(): + """Load the API description documents found by `list_api_descriptions`.""" + for name, version, path in list_api_descriptions(): + description = path.read_text("utf-8") + yield name, version, json.loads(description) + + +api_descriptions = sorted(load_api_descriptions(), key=itemgetter(1)) +assert len(api_descriptions) != 0 + + +class DescriptionHandler(http.server.BaseHTTPRequestHandler): + """An HTTP request handler that serves only API descriptions. + + The `desc` attribute ought to be specified, for example by subclassing, or + by using the `make` class-method. + + The `content_type` attribute can be overridden to simulate a different + Content-Type header for the description. + """ + + # Override these in subclasses. + description = b'{"resources": []}' + content_type = "application/json" + + @classmethod + def make(cls, description=description): + return type("DescriptionHandler", (cls,), {"description": description}) + + def setup(self): + super(DescriptionHandler, self).setup() + self.logs = [] + + def log_message(self, *args): + """By default logs go to stdout/stderr. Instead, capture them.""" + self.logs.append(args) + + def do_GET(self): + version_match = re.match(r"/MAAS/api/([0-9.]+)/describe/$", self.path) + if version_match is None: + self.send_error(http.HTTPStatus.NOT_FOUND) + else: + self.send_response(http.HTTPStatus.OK) + self.send_header("Content-Type", self.content_type) + self.send_header("Content-Length", str(len(self.description))) + self.end_headers() + self.wfile.write(self.description) + + +class DescriptionServer(fixtures.Fixture): + """Fixture to start up an HTTP server for API descriptions only. + + :ivar handler: A `DescriptionHandler` subclass. + :ivar server: An `http.server.HTTPServer` instance. + :ivar url: A URL that points to the API that `server` is mocking. + """ + + def __init__(self, description=DescriptionHandler.description): + super(DescriptionServer, self).__init__() + self.description = description + + def _setUp(self): + self.handler = DescriptionHandler.make(self.description) + self.server = http.server.HTTPServer(("", 0), self.handler) + self.url = "http://%s:%d/MAAS/api/2.0/" % self.server.server_address + threading.Thread(target=self.server.serve_forever).start() + self.addCleanup(self.server.server_close) + self.addCleanup(self.server.shutdown) diff --git a/maas/client/bones/testing/api20.json b/maas/client/bones/testing/api20.json new file mode 100644 index 00000000..6f2c7bba --- /dev/null +++ b/maas/client/bones/testing/api20.json @@ -0,0 +1,2731 @@ +{ + "doc": "MAAS API", + "hash": "ad0d8bb110f4b629278ceaef279948b7cf33db41", + "resources": [ + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create an authorisation OAuth token and OAuth consumer.\n\n:return: a json dict with three keys: 'token_key',\n 'token_secret' and 'consumer_key' (e.g.\n {token_key: 's65244576fgqs', token_secret: 'qsdfdhv34',\n consumer_key: '68543fhj854fg'}).\n:rtype: string (json)", + "method": "POST", + "name": "create_authorisation_token", + "op": "create_authorisation_token", + "restful": false + }, + { + "doc": "Delete an authorisation OAuth token and the related OAuth consumer.\n\n:param token_key: The key of the token to be deleted.\n:type token_key: unicode", + "method": "POST", + "name": "delete_authorisation_token", + "op": "delete_authorisation_token", + "restful": false + } + ], + "doc": "Manage the current logged-in user.", + "name": "AccountHandler", + "params": [], + "path": "/MAAS/api/2.0/account/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/" + }, + "name": "AccountHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete cache set on node.\n\nReturns 400 if the cache set is in use.\nReturns 404 if the node or cache set is not found.\nReturns 409 if the node is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read bcache cache set on node.\n\nReturns 404 if the node or cache set is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Delete bcache on node.\n\n:param cache_device: Cache block device to replace current one.\n:param cache_partition: Cache partition to replace current one.\n\nSpecifying both a cache_device and a cache_partition is not allowed.\n\nReturns 404 if the node or the cache set is not found.\nReturns 409 if the node is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache cache set on a node.", + "name": "BcacheCacheSetHandler", + "params": [ + "system_id", + "cache_set_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache-cache-set/{cache_set_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache-cache-set/{cache_set_id}/" + }, + "name": "BcacheCacheSetHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Creates a Bcache Cache Set.\n\n:param cache_device: Cache block device.\n:param cache_partition: Cache partition.\n\nSpecifying both a cache_device and a cache_partition is not allowed.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all bcache cache sets belonging to node.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache cache sets on a node.", + "name": "BcacheCacheSetsHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache-cache-sets/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache-cache-sets/" + }, + "name": "BcacheCacheSetsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete bcache on node.\n\nReturns 404 if the node or bcache is not found.\nReturns 409 if the node is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read bcache device on node.\n\nReturns 404 if the node or bcache is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Delete bcache on node.\n\n:param name: Name of the Bcache.\n:param uuid: UUID of the Bcache.\n:param cache_set: Cache set to replace current one.\n:param backing_device: Backing block device to replace current one.\n:param backing_partition: Backing partition to replace current one.\n:param cache_mode: Cache mode (writeback, writethrough, writearound).\n\nSpecifying both a device and a partition for a given role (cache or\nbacking) is not allowed.\n\nReturns 404 if the node or the bcache is not found.\nReturns 409 if the node is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache device on a node.", + "name": "BcacheHandler", + "params": [ + "system_id", + "bcache_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache/{bcache_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache/{bcache_id}/" + }, + "name": "BcacheHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Creates a Bcache.\n\n:param name: Name of the Bcache.\n:param uuid: UUID of the Bcache.\n:param cache_set: Cache set.\n:param backing_device: Backing block device.\n:param backing_partition: Backing partition.\n:param cache_mode: Cache mode (WRITEBACK, WRITETHROUGH, WRITEAROUND).\n\nSpecifying both a device and a partition for a given role (cache or\nbacking) is not allowed.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all bcache devices belonging to node.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache devices on a node.", + "name": "BcachesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/" + }, + "name": "BcachesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Add a tag to block device on node.\n\n:param tag: The tag being added.\n\nReturns 404 if the node or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the node is not Ready.", + "method": "GET", + "name": "add_tag", + "op": "add_tag", + "restful": false + }, + { + "doc": "Delete block device on node.\n\nReturns 404 if the node or block device is not found.\nReturns 403 if the user is not allowed to delete the block device.\nReturns 409 if the node is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Format block device with filesystem.\n\n:param fstype: Type of filesystem.\n:param uuid: UUID of the filesystem.\n\nReturns 403 when the user doesn't have the ability to format the block device.\nReturns 404 if the node or block device is not found.\nReturns 409 if the node is not Ready or Allocated.", + "method": "POST", + "name": "format", + "op": "format", + "restful": false + }, + { + "doc": "Mount the filesystem on block device.\n\n:param mount_point: Path on the filesystem to mount.\n\nReturns 403 when the user doesn't have the ability to mount the block device.\nReturns 404 if the node or block device is not found.\nReturns 409 if the node is not Ready or Allocated.", + "method": "POST", + "name": "mount", + "op": "mount", + "restful": false + }, + { + "doc": "Read block device on node.\n\nReturns 404 if the node or block device is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Remove a tag from block device on node.\n\n:param tag: The tag being removed.\n\nReturns 404 if the node or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the node is not Ready.", + "method": "GET", + "name": "remove_tag", + "op": "remove_tag", + "restful": false + }, + { + "doc": "Set this block device as the boot disk for the node.\n\nReturns 400 if the block device is a virtual block device.\nReturns 404 if the node or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the node is not Ready or Allocated.", + "method": "POST", + "name": "set_boot_disk", + "op": "set_boot_disk", + "restful": false + }, + { + "doc": "Unformat block device with filesystem.\n\nReturns 400 if the block device is not formatted, currently mounted, or part of a filesystem group.\nReturns 403 when the user doesn't have the ability to unformat the block device.\nReturns 404 if the node or block device is not found.\nReturns 409 if the node is not Ready or Allocated.", + "method": "POST", + "name": "unformat", + "op": "unformat", + "restful": false + }, + { + "doc": "Unmount the filesystem on block device.\n\nReturns 400 if the block device is not formatted or not currently mounted.\nReturns 403 when the user doesn't have the ability to unmount the block device.\nReturns 404 if the node or block device is not found.\nReturns 409 if the node is not Ready or Allocated.", + "method": "POST", + "name": "unmount", + "op": "unmount", + "restful": false + }, + { + "doc": "Update block device on node.\n\nFields for physical block device:\n:param name: Name of the block device.\n:param model: Model of the block device.\n:param serial: Serial number of the block device.\n:param id_path: (optional) Only used if model and serial cannot be provided. This should be a path that is fixed and doesn't change depending on the boot order or kernel version.\n:param size: Size of the block device.\n:param block_size: Block size of the block device.\n\nFields for virtual block device:\n:param name: Name of the block device.\n:param uuid: UUID of the block device.\n:param size: Size of the block device. (Only allowed for logical volumes.)\n\nReturns 404 if the node or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the node is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a block device on a node.", + "name": "BlockDeviceHandler", + "params": [ + "system_id", + "device_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/" + }, + "name": "BlockDeviceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a physical block device.\n\n:param name: Name of the block device.\n:param model: Model of the block device.\n:param serial: Serial number of the block device.\n:param id_path: (optional) Only used if model and serial cannot be\n provided. This should be a path that is fixed and doesn't change\n depending on the boot order or kernel version.\n:param size: Size of the block device.\n:param block_size: Block size of the block device.\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all block devices belonging to node.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage block devices on a node.", + "name": "BlockDevicesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/" + }, + "name": "BlockDevicesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete boot resource.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot resource.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot resource.", + "name": "BootResourceHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/boot-resources/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/" + }, + "name": "BootResourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Uploads a new boot resource.\n\n:param name: Name of the boot resource.\n:param title: Title for the boot resource.\n:param architecture: Architecture the boot resource supports.\n:param filetype: Filetype for uploaded content. (Default: tgz)\n:param content: Image content. Note: this is not a normal parameter,\n but a file upload.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Import the boot resources.", + "method": "POST", + "name": "import", + "op": "import", + "restful": false + }, + { + "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the boot resources.", + "name": "BootResourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/boot-resources/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/" + }, + "name": "BootResourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific boot source.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot source.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a specific boot source.\n\n:param url: The URL of the BootSource.\n:param keyring_filename: The path to the keyring file for this\n BootSource.\n:param keyring_filename: The GPG keyring for this BootSource,\n base64-encoded data.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot source.", + "name": "BootSourceHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/boot-sources/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/" + }, + "name": "BootSourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific boot source.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot source selection.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a specific boot source selection.\n\n:param release: The release for which to import resources.\n:param arches: The list of architectures for which to import resources.\n:param subarches: The list of subarchitectures for which to import\n resources.\n:param labels: The list of labels for which to import resources.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot source selection.", + "name": "BootSourceSelectionHandler", + "params": [ + "boot_source_id", + "id" + ], + "path": "/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/{id}/" + }, + "name": "BootSourceSelectionHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new boot source selection.\n\n:param release: The release for which to import resources.\n:param arches: The architecture list for which to import resources.\n:param subarches: The subarchitecture list for which to import\n resources.\n:param labels: The label lists for which to import resources.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List boot source selections.\n\nGet a listing of a boot source's selections.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of boot source selections.", + "name": "BootSourceSelectionsHandler", + "params": [ + "boot_source_id" + ], + "path": "/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/" + }, + "name": "BootSourceSelectionsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new boot source.\n\n:param url: The URL of the BootSource.\n:param keyring_filename: The path to the keyring file for\n this BootSource.\n:param keyring_data: The GPG keyring for this BootSource,\n base64-encoded.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List boot sources.\n\nGet a listing of boot sources.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of boot sources.", + "name": "BootSourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/boot-sources/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/" + }, + "name": "BootSourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a commissioning script.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a commissioning script.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a commissioning script.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", + "name": "CommissioningScriptHandler", + "params": [ + "name" + ], + "path": "/MAAS/api/2.0/commissioning-scripts/{name}", + "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}" + }, + "name": "CommissioningScriptHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new commissioning script.\n\nEach commissioning script is identified by a unique name.\n\nBy convention the name should consist of a two-digit number, a dash,\nand a brief descriptive identifier consisting only of ASCII\ncharacters. You don't need to follow this convention, but not doing\nso opens you up to risks w.r.t. encoding and ordering. The name must\nnot contain any whitespace, quotes, or apostrophes.\n\nA commissioning node will run each of the scripts in lexicographical\norder. There are no promises about how non-ASCII characters are\nsorted, or even how upper-case letters are sorted relative to\nlower-case letters. So where ordering matters, use unique numbers.\n\nScripts built into MAAS will have names starting with \"00-maas\" or\n\"99-maas\" to ensure that they run first or last, respectively.\n\nUsually a commissioning script will be just that, a script. Ideally a\nscript should be ASCII text to avoid any confusion over encoding. But\nin some cases a commissioning script might consist of a binary tool\nprovided by a hardware vendor. Either way, the script gets passed to\nthe commissioning node in the exact form in which it was uploaded.\n\n:param name: Unique identifying name for the script. Names should\n follow the pattern of \"25-burn-in-hard-disk\" (all ASCII, and with\n numbers greater than zero, and generally no \"weird\" characters).\n:param content: A script file, to be uploaded in binary form. Note:\n this is not a normal parameter, but a file upload. Its filename\n is ignored; MAAS will know it by the name you pass to the request.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List commissioning scripts.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", + "name": "CommissioningScriptsHandler", + "params": [], + "path": "/MAAS/api/2.0/commissioning-scripts/", + "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/" + }, + "name": "CommissioningScriptsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete dnsresource.\n\nReturns 403 if the user does not have permission to delete the\ndnsresource.\nReturns 404 if the dnsresource is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update dnsresource.\n\n:param fqdn: Hostname (with domain) for the dnsresource.\n:param ip_address: Address to assign to the dnsresource.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the dnsresource is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresource.", + "name": "DNSResourceHandler", + "params": [ + "dnsresource_id" + ], + "path": "/MAAS/api/2.0/dnsresources/{dnsresource_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{dnsresource_id}/" + }, + "name": "DNSResourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete dnsresourcerecord.\n\nReturns 403 if the user does not have permission to delete the\ndnsresourcerecord.\nReturns 404 if the dnsresourcerecord is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update dnsresourcerecord.\n\n:param rrtype: Resource Type\n:param rrdata: Resource Data (everything to the right of Type.)\n\nReturns 403 if the user does not have permission to update the\ndnsresourcerecord.\nReturns 404 if the dnsresourcerecord is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresourcerecord.", + "name": "DNSResourceRecordHandler", + "params": [ + "dnsresourcerecord_id" + ], + "path": "/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/" + }, + "name": "DNSResourceRecordHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a dnsresourcerecord.\n\n:param fqdn: Hostname (with domain) for the dnsresource. Either fqdn\n or (name, domain) must be specified. Fqdn is ignored if either\n name or domain is given.\n:param name: Hostname (without domain)\n:param domain: Domain (name or id)\n:param rrtype: resource type to create\n:param rrdata: resource data (everything to the right of\n resource type.)", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all dnsresourcerecords.\n\n:param domain: restrict the listing to entries for the domain.\n:param name: restrict the listing to entries of the given name.\n:param rrtype: restrict the listing to entries which have\n records of the given rrtype.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresourcerecords.", + "name": "DNSResourceRecordsHandler", + "params": [], + "path": "/MAAS/api/2.0/dnsresourcerecords/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/" + }, + "name": "DNSResourceRecordsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a dnsresource.\n\n:param fqdn: Hostname (with domain) for the dnsresource. Either fqdn\n or (name, domain) must be specified. Fqdn is ignored if either\n name or domain is given.\n:param name: Hostname (without domain)\n:param domain: Domain (name or id)\n:param address_ttl: Default ttl for entries in this zone.\n:param ip_addresses: (optional) Address (ip or id) to assign to the\n dnsresource.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all resources for the specified criteria.\n\n:param domain: restrict the listing to entries for the domain.\n:param name: restrict the listing to entries of the given name.\n:param rrtype: restrict the listing to entries which have\n records of the given rrtype.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresources.", + "name": "DNSResourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/dnsresources/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/" + }, + "name": "DNSResourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific Device.\n\nReturns 404 if the device is not found.\nReturns 403 if the user does not have permission to delete the device.\nReturns 204 if the device is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a specific device.\n\nReturns 404 if the device is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a specific device.\n\n:param hostname: The new hostname for this device.\n:param parent: Optional system_id to indicate this device's parent.\n If the parent is already set and this parameter is omitted,\n the parent will be unchanged.\n:type hostname: unicode\n\nReturns 404 if the device is not found.\nReturns 403 if the user does not have permission to update the device.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", + "name": "DeviceHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/devices/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/" + }, + "name": "DeviceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new device.\n\n:param mac_addresses: One or more MAC addresses for the device.\n:param hostname: A hostname. If not given, one will be generated.\n:param parent: The system id of the parent. Optional.", + "method": "POST", + "name": "create", + "op": "create", + "restful": false + }, + { + "doc": "Create a new device.\n\n:param mac_addresses: One or more MAC addresses for the device.\n:param hostname: A hostname. If not given, one will be generated.\n:param parent: The system id of the parent. Optional.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List devices visible to the user, optionally filtered by criteria.\n\n:param hostname: An optional list of hostnames. Only devices with\n matching hostnames will be returned.\n:type hostname: iterable\n:param mac_address: An optional list of MAC addresses. Only\n devices with matching MAC addresses will be returned.\n:type mac_address: iterable\n:param id: An optional list of system ids. Only devices with\n matching system ids will be returned.\n:type id: iterable", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of all the devices in the MAAS.", + "name": "DevicesHandler", + "params": [], + "path": "/MAAS/api/2.0/devices/", + "uri": "http://localhost:5240/MAAS/api/2.0/devices/" + }, + "name": "DevicesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete domain.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the domain is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read domain.\n\nReturns 404 if the domain is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update domain.\n\n:param name: Name of the domain.\n:param authoritative: True if we are authoritative for this domain.\n:param ttl: The default TTL for this domain.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the domain is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage domain.", + "name": "DomainHandler", + "params": [ + "domain_id" + ], + "path": "/MAAS/api/2.0/domains/{domain_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/domains/{domain_id}/" + }, + "name": "DomainHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all domains.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage domains.", + "name": "DomainsHandler", + "params": [], + "path": "/MAAS/api/2.0/domains/", + "uri": "http://localhost:5240/MAAS/api/2.0/domains/" + }, + "name": "DomainsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List Node events, optionally filtered by various criteria via\nURL query parameters.\n\n:param hostname: An optional hostname. Only events relating to the node\n with the matching hostname will be returned. This can be specified\n multiple times to get events relating to more than one node.\n:param mac_address: An optional list of MAC addresses. Only\n nodes with matching MAC addresses will be returned.\n:param id: An optional list of system ids. Only nodes with\n matching system ids will be returned.\n:param zone: An optional name for a physical zone. Only nodes in the\n zone will be returned.\n:param agent_name: An optional agent name. Only nodes with\n matching agent names will be returned.\n:param level: Desired minimum log level of returned events. Returns\n this level of events and greater. Choose from: WARNING, ERROR, INFO, CRITICAL, DEBUG.\n The default is INFO.", + "method": "GET", + "name": "query", + "op": "query", + "restful": false + } + ], + "doc": "Retrieve filtered node events.\n\nA specific Node's events is identified by specifying one or more\nids, hostnames, or mac addresses as a list.", + "name": "EventsHandler", + "params": [], + "path": "/MAAS/api/2.0/events/", + "uri": "http://localhost:5240/MAAS/api/2.0/events/" + }, + "name": "EventsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read fabric.\n\nReturns 404 if the fabric is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric.\n\nReturns 404 if the fabric is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage fabric.", + "name": "FabricHandler", + "params": [ + "fabric_id" + ], + "path": "/MAAS/api/2.0/fabrics/{fabric_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/" + }, + "name": "FabricHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all fabrics.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage fabrics.", + "name": "FabricsHandler", + "params": [], + "path": "/MAAS/api/2.0/fabrics/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/" + }, + "name": "FabricsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update fannetwork.\n\n:param name: Name of the fannetwork.\n:param overlay: Overlay network\n:param underlay: Underlay network\n:param dhcp: confiugre dhcp server for overlay net\n:param host_reserve: number of IP addresses to reserve for host\n:param bridge: override bridge name\n:param off: put this int he config, but disable it.\n\nReturns 404 if the fannetwork is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage Fan Network.", + "name": "FanNetworkHandler", + "params": [ + "fannetwork_id" + ], + "path": "/MAAS/api/2.0/fannetworks/{fannetwork_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{fannetwork_id}/" + }, + "name": "FanNetworkHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a fannetwork.\n\n:param name: Name of the fannetwork.\n:param overlay: Overlay network\n:param underlay: Underlay network\n:param dhcp: confiugre dhcp server for overlay net\n:param host_reserve: number of IP addresses to reserve for host\n:param bridge: override bridge name\n:param off: put this int he config, but disable it.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all fannetworks.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage Fan Networks.", + "name": "FanNetworksHandler", + "params": [], + "path": "/MAAS/api/2.0/fannetworks/", + "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/" + }, + "name": "FanNetworksHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a FileStorage object.", + "method": "POST", + "name": "delete", + "op": "delete", + "restful": false + }, + { + "doc": "Delete a FileStorage object.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", + "name": "FileHandler", + "params": [ + "filename" + ], + "path": "/MAAS/api/2.0/files/{filename}/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/" + }, + "name": "FileHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Get a named file from the file storage.\n\n:param filename: The exact name of the file you want to get.\n:type filename: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get", + "op": "get", + "restful": false + }, + { + "doc": "Get a file from the file storage using its key.\n\n:param key: The exact key of the file you want to get.\n:type key: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get_by_key", + "op": "get_by_key", + "restful": false + } + ], + "doc": "Anonymous file operations.\n\nThis is needed for Juju. The story goes something like this:\n\n- The Juju provider will upload a file using an \"unguessable\" name.\n\n- The name of this file (or its URL) will be shared with all the agents in\n the environment. They cannot modify the file, but they can access it\n without credentials.", + "name": "AnonFilesHandler", + "params": [], + "path": "/MAAS/api/2.0/files/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/" + }, + "auth": { + "actions": [ + { + "doc": "Add a new file to the file storage.\n\n:param filename: The file name to use in the storage.\n:type filename: string\n:param file: Actual file data with content type\n application/octet-stream\n\nReturns 400 if any of these conditions apply:\n - The filename is missing from the parameters\n - The file data is missing\n - More than one file is supplied", + "method": "POST", + "name": "add", + "op": "add", + "restful": false + }, + { + "doc": "Get a named file from the file storage.\n\n:param filename: The exact name of the file you want to get.\n:type filename: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get", + "op": "get", + "restful": false + }, + { + "doc": "Get a file from the file storage using its key.\n\n:param key: The exact key of the file you want to get.\n:type key: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get_by_key", + "op": "get_by_key", + "restful": false + }, + { + "doc": "List the files from the file storage.\n\nThe returned files are ordered by file name and the content is\nexcluded.\n\n:param prefix: Optional prefix used to filter out the returned files.\n:type prefix: string", + "method": "GET", + "name": "list", + "op": "list", + "restful": false + } + ], + "doc": "Manage the collection of all the files in this MAAS.", + "name": "FilesHandler", + "params": [], + "path": "/MAAS/api/2.0/files/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/" + }, + "name": "FilesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List IPAddresses.\n\nGet a listing of all IPAddresses allocated to the requesting user.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Release an IP address that was previously reserved by the user.\n\n:param ip: The IP address to release.\n:type ip: unicode\n\nReturns 404 if the provided IP address is not found.", + "method": "POST", + "name": "release", + "op": "release", + "restful": false + }, + { + "doc": "Reserve an IP address for use outside of MAAS.\n\nReturns an IP adddress, which MAAS will not allow any of its known\nnodes to use; it is free for use by the requesting user until released\nby the user.\n\nThe user may supply either a subnet or a specific IP address within a\nsubnet.\n\n:param subnet: CIDR representation of the subnet on which the IP\n reservation is required. e.g. 10.1.2.0/24\n:param ip_address: The IP address, which must be within\n a known subnet.\n:param hostname: The hostname to use for the specified IP address\n:param mac: The MAC address that should be linked to this reservation.\n\nReturns 400 if there is no subnet in MAAS matching the provided one,\nor a ip_address is supplied, but a corresponding subnet\ncould not be found.\nReturns 503 if there are no more IP addresses available.", + "method": "POST", + "name": "reserve", + "op": "reserve", + "restful": false + } + ], + "doc": "Manage IP addresses allocated by MAAS.", + "name": "IPAddressesHandler", + "params": [], + "path": "/MAAS/api/2.0/ipaddresses/", + "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/" + }, + "name": "IPAddressesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Link interface to a subnet.\n\n:param mode: AUTO, DHCP, STATIC or LINK_UP connection to subnet.\n:param subnet: Subnet linked to interface.\n:param ip_address: IP address for the interface in subnet. Only used\n when mode is STATIC. If not provided an IP address from subnet\n will be auto selected.\n:param default_gateway: True sets the gateway IP address for the subnet\n as the default gateway for the node this interface belongs to.\n Option can only be used with the AUTO and STATIC modes.\n\nMode definitions:\nAUTO - Assign this interface a static IP address from the provided\nsubnet. The subnet must be a managed subnet. The IP address will\nnot be assigned until the node goes to be deployed.\n\nDHCP - Bring this interface up with DHCP on the given subnet. Only\none subnet can be set to DHCP. If the subnet is managed this\ninterface will pull from the dynamic IP range.\n\nSTATIC - Bring this interface up with a STATIC IP address on the\ngiven subnet. Any number of STATIC links can exist on an interface.\n\nLINK_UP - Bring this interface up only on the given subnet. No IP\naddress will be assigned to this interface. The interface cannot\nhave any current AUTO, DHCP or STATIC links.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "link_subnet", + "op": "link_subnet", + "restful": false + }, + { + "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Set the node to use this interface as the default gateway.\n\nIf this interface has more than one subnet with a gateway IP in the\nsame IP address family then specifying the ID of the link on\nthis interface is required.\n\n:param link_id: ID of the link on this interface to select the\n default gateway IP address from.\n\nReturns 400 if the interface has not AUTO or STATIC links.\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "set_default_gateway", + "op": "set_default_gateway", + "restful": false + }, + { + "doc": "Unlink interface to a subnet.\n\n:param id: ID of the link on the interface to remove.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "unlink_subnet", + "op": "unlink_subnet", + "restful": false + }, + { + "doc": "Update interface on node.\n\nFields for physical interface:\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to.\n\nFields for bond interface:\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parents: Parent interfaces that make this bond.\n\nFields for VLAN interface:\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFollowing are extra parameters that can be set on all interface types:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nFollowing are parameters specific to bonds:\n\n:param bond-mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond-miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond-downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond-updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond-lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond-xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n\nSupported bonding modes (bond-mode):\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nReturns 404 if the node or interface is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a node's or device's interface.", + "name": "InterfaceHandler", + "params": [ + "system_id", + "interface_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/{interface_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/{interface_id}/" + }, + "name": "InterfaceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a bond interface on a machine.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parents: Parent interfaces that make this bond.\n\nFollowing are parameters specific to bonds:\n\n:param bond_mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond_miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond_downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond_updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond_lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond_xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n (Default: layer2)\n\nSupported bonding modes (bond-mode):\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_bond", + "op": "create_bond", + "restful": false + }, + { + "doc": "Create a physical interface on a machine, device, or\nrack controller.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_physical", + "op": "create_physical", + "restful": false + }, + { + "doc": "Create a VLAN interface on a machine.\n\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_vlan", + "op": "create_vlan", + "restful": false + }, + { + "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage interfaces on a node or device.", + "name": "InterfacesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/" + }, + "name": "InterfacesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete license key.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read license key.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update license key.\n\n:param osystem: Operating system that the key belongs to.\n:param distro_series: OS release that the key belongs to.\n:param license_key: License key for osystem/distro_series combo.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a license key.", + "name": "LicenseKeyHandler", + "params": [ + "osystem", + "distro_series" + ], + "path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", + "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}" + }, + "name": "LicenseKeyHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Define a license key.\n\n:param osystem: Operating system that the key belongs to.\n:param distro_series: OS release that the key belongs to.\n:param license_key: License key for osystem/distro_series combo.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List license keys.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the license keys.", + "name": "LicenseKeysHandler", + "params": [], + "path": "/MAAS/api/2.0/license-keys/", + "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/" + }, + "name": "LicenseKeysHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Get a config value.\n\n:param name: The name of the config item to be retrieved.\n:type name: unicode\n\nAvailable configuration items:\n- default_dns_ttl: Default Time-To-Live for the DNS.. If no TTL value is specified at a more specific point this is how long DNS responses are valid, in seconds.\n- main_archive: Main archive. Archive used by nodes to retrieve packages for Intel architectures. E.g. http://archive.ubuntu.com/ubuntu.\n- curtin_verbose: Run the fast-path installer with higher verbosity. This provides more detail in the installation logs..\n- kernel_opts: Boot parameters to pass to the kernel by default.\n- upstream_dns: Upstream DNS used to resolve domains not managed by this MAAS (space-separated IP addresses). Only used when MAAS is running its own DNS server. This value is used as the value of 'forwarders' in the DNS server config.\n- maas_name: MAAS name.\n- enable_disk_erasing_on_release: Erase nodes' disks prior to releasing..\n- http_proxy: Proxy for APT and HTTP/HTTPS. This will be passed onto provisioned nodes to use as a proxy for APT traffic. MAAS also uses the proxy for downloading boot images. If no URL is provided, the built-in MAAS proxy will be used.\n- enable_http_proxy: Enable the use of an APT and HTTP/HTTPS proxy. Provision nodes to use the built-in HTTP proxy (or user specified proxy) for APT. MAAS also uses the proxy for downloading boot images.\n- default_distro_series: Default OS release used for deployment.\n- windows_kms_host: Windows KMS activation host. FQDN or IP address of the host that provides the KMS Windows activation service. (Only needed for Windows deployments using KMS activation.)\n- dnssec_validation: Enable DNSSEC validation of upstream zones. Only used when MAAS is running its own DNS server. This value is used as the value of 'dnssec_validation' in the DNS server config.\n- boot_images_auto_import: Automatically import/refresh the boot images every 60 minutes.\n- ntp_server: Address of NTP server for nodes. NTP server address passed to nodes via a DHCP response. e.g. ntp.ubuntu.com\n- commissioning_distro_series: Default Ubuntu release used for commissioning.\n- default_osystem: Default operating system used for deployment.\n- default_storage_layout: Default storage layout. Storage layout that is applied to a node when it is commissioned. Available choices are: 'flat' (Flat layout), 'lvm' (LVM layout), 'bcache' (Bcache layout).\n- default_min_hwe_kernel: Default Minimum Kernel Version. The default minimum kernel version used on all new and commissioned nodes.\n- ports_archive: Ports archive. Archive used by nodes to retrieve packages for non-Intel architectures. E.g. http://ports.ubuntu.com/ubuntu-ports.\n- enable_third_party_drivers: Enable the installation of proprietary drivers (i.e. HPVSA).", + "method": "GET", + "name": "get_config", + "op": "get_config", + "restful": false + }, + { + "doc": "Set a config value.\n\n:param name: The name of the config item to be set.\n:type name: unicode\n:param value: The value of the config item to be set.\n:type value: json object\n\nAvailable configuration items:\n- default_dns_ttl: Default Time-To-Live for the DNS.. If no TTL value is specified at a more specific point this is how long DNS responses are valid, in seconds.\n- main_archive: Main archive. Archive used by nodes to retrieve packages for Intel architectures. E.g. http://archive.ubuntu.com/ubuntu.\n- curtin_verbose: Run the fast-path installer with higher verbosity. This provides more detail in the installation logs..\n- kernel_opts: Boot parameters to pass to the kernel by default.\n- upstream_dns: Upstream DNS used to resolve domains not managed by this MAAS (space-separated IP addresses). Only used when MAAS is running its own DNS server. This value is used as the value of 'forwarders' in the DNS server config.\n- maas_name: MAAS name.\n- enable_disk_erasing_on_release: Erase nodes' disks prior to releasing..\n- http_proxy: Proxy for APT and HTTP/HTTPS. This will be passed onto provisioned nodes to use as a proxy for APT traffic. MAAS also uses the proxy for downloading boot images. If no URL is provided, the built-in MAAS proxy will be used.\n- enable_http_proxy: Enable the use of an APT and HTTP/HTTPS proxy. Provision nodes to use the built-in HTTP proxy (or user specified proxy) for APT. MAAS also uses the proxy for downloading boot images.\n- default_distro_series: Default OS release used for deployment.\n- windows_kms_host: Windows KMS activation host. FQDN or IP address of the host that provides the KMS Windows activation service. (Only needed for Windows deployments using KMS activation.)\n- dnssec_validation: Enable DNSSEC validation of upstream zones. Only used when MAAS is running its own DNS server. This value is used as the value of 'dnssec_validation' in the DNS server config.\n- boot_images_auto_import: Automatically import/refresh the boot images every 60 minutes.\n- ntp_server: Address of NTP server for nodes. NTP server address passed to nodes via a DHCP response. e.g. ntp.ubuntu.com\n- commissioning_distro_series: Default Ubuntu release used for commissioning.\n- default_osystem: Default operating system used for deployment.\n- default_storage_layout: Default storage layout. Storage layout that is applied to a node when it is commissioned. Available choices are: 'flat' (Flat layout), 'lvm' (LVM layout), 'bcache' (Bcache layout).\n- default_min_hwe_kernel: Default Minimum Kernel Version. The default minimum kernel version used on all new and commissioned nodes.\n- ports_archive: Ports archive. Archive used by nodes to retrieve packages for non-Intel architectures. E.g. http://ports.ubuntu.com/ubuntu-ports.\n- enable_third_party_drivers: Enable the installation of proprietary drivers (i.e. HPVSA).", + "method": "POST", + "name": "set_config", + "op": "set_config", + "restful": false + } + ], + "doc": "Manage the MAAS server.", + "name": "MaasHandler", + "params": [], + "path": "/MAAS/api/2.0/maas/", + "uri": "http://localhost:5240/MAAS/api/2.0/maas/" + }, + "name": "MaasHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Abort a machine's current operation.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nThis currently only supports aborting of the 'Disk Erasing' operation.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to abort the\ncurrent operation.", + "method": "POST", + "name": "abort", + "op": "abort", + "restful": false + }, + { + "doc": "Clear any set default gateways on the machine.\n\nThis will clear both IPv4 and IPv6 gateways on the machine. This will\ntransition the logic of identifing the best gateway to MAAS. This logic\nis determined based the following criteria:\n\n1. Managed subnets over unmanaged subnets.\n2. Bond interfaces over physical interfaces.\n3. Machine's boot interface over all other interfaces except bonds.\n4. Physical interfaces over VLAN interfaces.\n5. Sticky IP links over user reserved IP links.\n6. User reserved IP links over auto IP links.\n\nIf the default gateways need to be specific for this machine you can\nset which interface and subnet's gateway to use when this machine is\ndeployed with the `node-interfaces set-default-gateway` API.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to clear the default\ngateways.", + "method": "POST", + "name": "clear_default_gateways", + "op": "clear_default_gateways", + "restful": false + }, + { + "doc": "Begin commissioning process for a machine.\n\n:param enable_ssh: Whether to enable SSH for the commissioning\n environment using the user's SSH key(s).\n:type enable_ssh: bool ('0' for False, '1' for True)\n:param skip_networking: Whether to skip re-configuring the networking\n on the machine after the commissioning has completed.\n:type skip_networking: bool ('0' for False, '1' for True)\n:param skip_storage: Whether to skip re-configuring the storage\n on the machine after the commissioning has completed.\n:type skip_storage: bool ('0' for False, '1' for True)\n\nA machine in the 'ready', 'declared' or 'failed test' state may\ninitiate a commissioning cycle where it is checked out and tested\nin preparation for transitioning to the 'ready' state. If it is\nalready in the 'ready' state this is considered a re-commissioning\nprocess which is useful if commissioning tests were changed after\nit previously commissioned.\n\nReturns 404 if the machine is not found.", + "method": "POST", + "name": "commission", + "op": "commission", + "restful": false + }, + { + "doc": "Delete a specific Node.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to delete the node.\nReturns 204 if the node is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Deploy an operating system to a machine.\n\n:param user_data: If present, this blob of user-data to be made\n available to the machines through the metadata service.\n:type user_data: base64-encoded unicode\n:param distro_series: If present, this parameter specifies the\n OS release the machine will use.\n:type distro_series: unicode\n:param hwe_kernel: If present, this parameter specified the kernel to\n be used on the machine\n:type hwe_kernel: unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nIdeally we'd have MIME multipart and content-transfer-encoding etc.\ndeal with the encapsulation of binary data, but couldn't make it work\nwith the framework in reasonable time so went for a dumb, manual\nencoding instead.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to start the machine.\nReturns 503 if the start-up attempted to allocate an IP address,\nand there were no IP addresses available on the relevant cluster\ninterface.", + "method": "POST", + "name": "deploy", + "op": "deploy", + "restful": false + }, + { + "doc": "Obtain various system details.\n\nFor example, LLDP and ``lshw`` XML dumps.\n\nReturns a ``{detail_type: xml, ...}`` map, where\n``detail_type`` is something like \"lldp\" or \"lshw\".\n\nNote that this is returned as BSON and not JSON. This is for\nefficiency, but mainly because JSON can't do binary content\nwithout applying additional encoding like base-64.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "details", + "op": "details", + "restful": false + }, + { + "doc": "Return the rendered curtin configuration for the machine.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to get the curtin\nconfiguration.", + "method": "GET", + "name": "get_curtin_config", + "op": "get_curtin_config", + "restful": false + }, + { + "doc": "Mark a node as 'broken'.\n\nIf the node is allocated, release it first.\n\n:param comment: Optional comment for the event log. Will be\n displayed on the Node as an error description until marked fixed.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nbroken.", + "method": "POST", + "name": "mark_broken", + "op": "mark_broken", + "restful": false + }, + { + "doc": "Mark a broken node as fixed and set its status as 'ready'.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nfixed.", + "method": "POST", + "name": "mark_fixed", + "op": "mark_fixed", + "restful": false + }, + { + "doc": "Power off a machine.\n\n:param stop_mode: An optional power off mode. If 'soft',\n perform a soft power down if the machine's power type supports\n it, otherwise perform a hard power off. For all values other\n than 'soft', and by default, perform a hard power off. A\n soft power off generally asks the OS to shutdown the system\n gracefully before powering off, while a hard power off\n occurs immediately without any warning to the OS.\n:type stop_mode: unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to stop the machine.", + "method": "POST", + "name": "power_off", + "op": "power_off", + "restful": false + }, + { + "doc": "Turn on a machine.\n\n:param user_data: If present, this blob of user-data to be made\n available to the machines through the metadata service.\n:type user_data: base64-encoded unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nIdeally we'd have MIME multipart and content-transfer-encoding etc.\ndeal with the encapsulation of binary data, but couldn't make it work\nwith the framework in reasonable time so went for a dumb, manual\nencoding instead.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to start the machine.\nReturns 503 if the start-up attempted to allocate an IP address,\nand there were no IP addresses available on the relevant cluster\ninterface.", + "method": "POST", + "name": "power_on", + "op": "power_on", + "restful": false + }, + { + "doc": "Obtain power parameters.\n\nThis method is reserved for admin users and returns a 403 if the\nuser is not one.\n\nThis returns the power parameters, if any, configured for a\nnode. For some types of power control this will include private\ninformation such as passwords and secret keys.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "power_parameters", + "op": "power_parameters", + "restful": false + }, + { + "doc": "Query the power state of a node.\n\nSend a request to the machine's power controller which asks it about\nthe machine's state. The reply to this could be delayed by up to\n30 seconds while waiting for the power controller to respond.\nUse this method sparingly as it ties up an appserver thread\nwhile waiting.\n\n:param system_id: The machine to query.\n:return: a dict whose key is \"state\" with a value of one of\n 'on' or 'off'.\n\nReturns 404 if the machine is not found.\nReturns 503 (with explanatory text) if the power state could not\nbe queried.", + "method": "GET", + "name": "query_power_state", + "op": "query_power_state", + "restful": false + }, + { + "doc": "Read a specific Node.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Release a node. Opposite of `MachinesHandler.acquire`.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the machine is not found.\nReturns 403 if the user doesn't have permission to release the machine.\nReturns 409 if the machine is in a state where it may not be released.", + "method": "POST", + "name": "release", + "op": "release", + "restful": false + }, + { + "doc": "Changes the storage layout on the machine.\n\nThis can only be preformed on an allocated machine.\n\nNote: This will clear the current storage layout and any extra\nconfiguration and replace it will the new layout.\n\n:param storage_layout: Storage layout for the machine. (flat, lvm\n and bcache)\n\nThe following are optional for all layouts:\n\n:param boot_size: Size of the boot partition.\n:param root_size: Size of the root partition.\n:param root_device: Physical block device to place the root partition.\n\nThe following are optional for LVM:\n\n:param vg_name: Name of created volume group.\n:param lv_name: Name of created logical volume.\n:param lv_size: Size of created logical volume.\n\nThe following are optional for Bcache:\n\n:param cache_device: Physical block device to use as the cache device.\n:param cache_mode: Cache mode for bcache device. (writeback,\n writethrough, writearound)\n:param cache_size: Size of the cache partition to create on the cache\n device.\n:param cache_no_part: Don't create a partition on the cache device.\n Use the entire disk as the cache device.\n\nReturns 400 if the machine is currently not allocated.\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to set the storage\nlayout.", + "method": "POST", + "name": "set_storage_layout", + "op": "set_storage_layout", + "restful": false + }, + { + "doc": "Update a specific Machine.\n\n:param hostname: The new hostname for this machine.\n:type hostname: unicode\n:param architecture: The new architecture for this machine.\n:type architecture: unicode\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:type min_hwe_kernel: unicode\n:param power_type: The new power type for this machine. If you use the\n default value, power_parameters will be set to the empty string.\n Available to admin users.\n See the `Power types`_ section for a list of the available power\n types.\n:type power_type: unicode\n:param power_parameters_{param1}: The new value for the 'param1'\n power parameter. Note that this is dynamic as the available\n parameters depend on the selected value of the Machine's\n power_type. For instance, if the power_type is 'ether_wake', the\n only valid parameter is 'power_address' so one would want to pass\n 'myaddress' as the value of the 'power_parameters_power_address'\n parameter. Available to admin users. See the `Power types`_ section\n for a list of the available power parameters for each power type.\n:type power_parameters_{param1}: unicode\n:param power_parameters_skip_check: Whether or not the new power\n parameters for this machine should be checked against the expected\n power parameters for the machine's power type ('true' or 'false').\n The default is 'false'.\n:type power_parameters_skip_check: unicode\n:param zone: Name of a valid physical zone in which to place this\n machine\n:type zone: unicode\n:param swap_size: Specifies the size of the swap file, in bytes. Field\n accept K, M, G and T suffixes for values expressed respectively in\n kilobytes, megabytes, gigabytes and terabytes.\n:type swap_size: unicode\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to update the machine.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", + "name": "MachineHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/machines/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/" + }, + "name": "MachineHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401.", + "method": "POST", + "name": "accept", + "op": "accept", + "restful": false + }, + { + "doc": "Create a new Machine.\n\nAdding a server to a MAAS puts it on a path that will wipe its disks\nand re-install its operating system, in the event that it PXE boots.\nIn anonymous enlistment (and when the enlistment is done by a\nnon-admin), the machine is held in the \"New\" state for approval by a\nMAAS admin.\n\nThe minimum data required is:\narchitecture= (e.g. \"i386/generic\")\nmac_addresses= (e.g. \"aa:bb:cc:dd:ee:ff\")\nautodetect_nodegroup=True\n\n:param architecture: A string containing the architecture type of\n the machine. (For example, \"i386\", or \"amd64\".) To determine the\n supported architectures, use the boot-resources endpoint.\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:param subarchitecture: A string containing the subarchitecture type\n of the machine. (For example, \"generic\" or \"hwe-t\".) To determine\n the supported subarchitectures, use the boot-resources endpoint.\n:param mac_addresses: One or more MAC addresses for the machine. To\n specify more than one MAC address, the parameter must be specified\n twice. (such as \"machines new mac_addresses=01:02:03:04:05:06\n mac_addresses=02:03:04:05:06:07\")\n:param hostname: A hostname. If not given, one will be generated.\n:param power_type: A power management type, if applicable (e.g.\n \"virsh\", \"ipmi\").\n:param autodetect_nodegroup: (boolean) Whether or not to attempt\n nodegroup detection for this machine. The nodegroup is determined\n based on the requestor's IP address range. (if the API request\n comes from an IP range within a known nodegroup, that nodegroup\n will be used.)\n:param nodegroup: The id of the nodegroup this machine belongs to.", + "method": "POST", + "name": "create", + "op": "create", + "restful": false + }, + { + "doc": "Create a new Machine.\n\nAdding a server to a MAAS puts it on a path that will wipe its disks\nand re-install its operating system, in the event that it PXE boots.\nIn anonymous enlistment (and when the enlistment is done by a\nnon-admin), the machine is held in the \"New\" state for approval by a\nMAAS admin.\n\nThe minimum data required is:\narchitecture= (e.g. \"i386/generic\")\nmac_addresses= (e.g. \"aa:bb:cc:dd:ee:ff\")\nautodetect_nodegroup=True\n\n:param architecture: A string containing the architecture type of\n the machine. (For example, \"i386\", or \"amd64\".) To determine the\n supported architectures, use the boot-resources endpoint.\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:param subarchitecture: A string containing the subarchitecture type\n of the machine. (For example, \"generic\" or \"hwe-t\".) To determine\n the supported subarchitectures, use the boot-resources endpoint.\n:param mac_addresses: One or more MAC addresses for the machine. To\n specify more than one MAC address, the parameter must be specified\n twice. (such as \"machines new mac_addresses=01:02:03:04:05:06\n mac_addresses=02:03:04:05:06:07\")\n:param hostname: A hostname. If not given, one will be generated.\n:param power_type: A power management type, if applicable (e.g.\n \"virsh\", \"ipmi\").\n:param autodetect_nodegroup: (boolean) Whether or not to attempt\n nodegroup detection for this machine. The nodegroup is determined\n based on the requestor's IP address range. (if the API request\n comes from an IP range within a known nodegroup, that nodegroup\n will be used.)\n:param nodegroup: The id of the nodegroup this machine belongs to.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Returns whether or not the given MAC address is registered within\nthis MAAS (and attached to a non-retired node).\n\n:param mac_address: The mac address to be checked.\n:type mac_address: unicode\n:return: 'true' or 'false'.\n:rtype: unicode\n\nReturns 400 if any mandatory parameters are missing.", + "method": "GET", + "name": "is_registered", + "op": "is_registered", + "restful": false + }, + { + "doc": null, + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Anonymous access to Machines.", + "name": "AnonMachinesHandler", + "params": [], + "path": "/MAAS/api/2.0/machines/", + "uri": "http://localhost:5240/MAAS/api/2.0/machines/" + }, + "auth": { + "actions": [ + { + "doc": "Accept declared machines into the MAAS.\n\nMachines can be enlisted in the MAAS anonymously or by non-admin users,\nas opposed to by an admin. These machines are held in the New\nstate; a MAAS admin must first verify the authenticity of these\nenlistments, and accept them.\n\nEnlistments can be accepted en masse, by passing multiple machines to\nthis call. Accepting an already accepted machine is not an error, but\naccepting one that is already allocated, broken, etc. is.\n\n:param machines: system_ids of the machines whose enlistment is to be\n accepted. (An empty list is acceptable).\n:return: The system_ids of any machines that have their status changed\n by this call. Thus, machines that were already accepted are\n excluded from the result.\n\nReturns 400 if any of the machines do not exist.\nReturns 403 if the user is not an admin.", + "method": "POST", + "name": "accept", + "op": "accept", + "restful": false + }, + { + "doc": "Accept all declared machines into the MAAS.\n\nMachines can be enlisted in the MAAS anonymously or by non-admin users,\nas opposed to by an admin. These machines are held in the New\nstate; a MAAS admin must first verify the authenticity of these\nenlistments, and accept them.\n\n:return: Representations of any machines that have their status changed\n by this call. Thus, machines that were already accepted are\n excluded from the result.", + "method": "POST", + "name": "accept_all", + "op": "accept_all", + "restful": false + }, + { + "doc": "Allocate an available machine for deployment.\n\nConstraints parameters can be used to allocate a machine that possesses\ncertain characteristics. All the constraints are optional and when\nmultiple constraints are provided, they are combined using 'AND'\nsemantics.\n\n:param name: Hostname of the returned machine.\n:type name: unicode\n:param arch: Architecture of the returned machine (e.g. 'i386/generic',\n 'amd64', 'armhf/highbank', etc.).\n:type arch: unicode\n:param cpu_count: The minium number of CPUs the returned machine must\n have.\n:type cpu_count: int\n:param mem: The minimum amount of memory (expressed in MB) the\n returned machine must have.\n:type mem: float\n:param tags: List of tags the returned machine must have.\n:type tags: list of unicodes\n:param not_tags: List of tags the acquired machine must not have.\n:type tags: List of unicodes.\n:param networks: List of networks (defined in MAAS) to which the\n machine must be attached. A network can be identified by the name\n assigned to it in MAAS; or by an `ip:` prefix followed by any IP\n address that falls within the network; or a `vlan:` prefix\n followed by a numeric VLAN tag, e.g. `vlan:23` for VLAN number 23.\n Valid VLAN tags must be in the range of 1 to 4095 inclusive.\n:type networks: list of unicodes\n:param not_networks: List of networks (defined in MAAS) to which the\n machine must not be attached. The returned machine won't be\n attached to any of the specified networks. A network can be\n identified by the name assigned to it in MAAS; or by an `ip:`\n prefix followed by any IP address that falls within the network; or\n a `vlan:` prefix followed by a numeric VLAN tag, e.g. `vlan:23` for\n VLAN number 23. Valid VLAN tags must be in the range of 1 to 4095\n inclusive.\n:type not_networks: list of unicodes\n:param zone: An optional name for a physical zone the acquired\n machine should be located in.\n:type zone: unicode\n:type not_in_zone: Optional list of physical zones from which the\n machine should not be acquired.\n:type not_in_zone: List of unicodes.\n:param agent_name: An optional agent name to attach to the\n acquired machine.\n:type agent_name: unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n:param dry_run: Optional boolean to indicate that the machine should\n not actually be acquired (this is for support/troubleshooting, or\n users who want to see which machine would match a constraint,\n without acquiring a machine). Defaults to False.\n:type dry_run: bool\n:param verbose: Optional boolean to indicate that the user would like\n additional verbosity in the constraints_by_type field (each\n constraint will be prefixed by `verbose_`, and contain the full\n data structure that indicates which machine(s) matched).\n:type verbose: bool\n\nReturns 409 if a suitable machine matching the constraints could not be\nfound.", + "method": "POST", + "name": "allocate", + "op": "allocate", + "restful": false + }, + { + "doc": "Create a new Machine.\n\nAdding a server to MAAS puts it on a path that will wipe its disks\nand re-install its operating system, in the event that it PXE boots.\nIn anonymous enlistment (and when the enlistment is done by a\nnon-admin), the machine is held in the \"New\" state for approval by a\nMAAS admin.\n\nThe minimum data required is:\narchitecture= (e.g. \"i386/generic\")\nmac_addresses= (e.g. \"aa:bb:cc:dd:ee:ff\")\nautodetect_nodegroup=True\n\n:param architecture: A string containing the architecture type of\n the machine. (For example, \"i386\", or \"amd64\".) To determine the\n supported architectures, use the boot-resources endpoint.\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:param subarchitecture: A string containing the subarchitecture type\n of the machine. (For example, \"generic\" or \"hwe-t\".) To determine\n the supported subarchitectures, use the boot-resources endpoint.\n:param mac_addresses: One or more MAC addresses for the machine. To\n specify more than one MAC address, the parameter must be specified\n twice. (such as \"machines new mac_addresses=01:02:03:04:05:06\n mac_addresses=02:03:04:05:06:07\")\n:param hostname: A hostname. If not given, one will be generated.\n:param power_type: A power management type, if applicable (e.g.\n \"virsh\", \"ipmi\").\n:param autodetect_nodegroup: (boolean) Whether or not to attempt\n nodegroup detection for this machine. The nodegroup is determined\n based on the requestor's IP address range. (if the API request\n comes from an IP range within a known nodegroup, that nodegroup\n will be used.)\n:param nodegroup: The id of the nodegroup this node belongs to.", + "method": "POST", + "name": "create", + "op": "create", + "restful": false + }, + { + "doc": "Create a new Machine.\n\nAdding a server to MAAS puts it on a path that will wipe its disks\nand re-install its operating system, in the event that it PXE boots.\nIn anonymous enlistment (and when the enlistment is done by a\nnon-admin), the machine is held in the \"New\" state for approval by a\nMAAS admin.\n\nThe minimum data required is:\narchitecture= (e.g. \"i386/generic\")\nmac_addresses= (e.g. \"aa:bb:cc:dd:ee:ff\")\nautodetect_nodegroup=True\n\n:param architecture: A string containing the architecture type of\n the machine. (For example, \"i386\", or \"amd64\".) To determine the\n supported architectures, use the boot-resources endpoint.\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:param subarchitecture: A string containing the subarchitecture type\n of the machine. (For example, \"generic\" or \"hwe-t\".) To determine\n the supported subarchitectures, use the boot-resources endpoint.\n:param mac_addresses: One or more MAC addresses for the machine. To\n specify more than one MAC address, the parameter must be specified\n twice. (such as \"machines new mac_addresses=01:02:03:04:05:06\n mac_addresses=02:03:04:05:06:07\")\n:param hostname: A hostname. If not given, one will be generated.\n:param power_type: A power management type, if applicable (e.g.\n \"virsh\", \"ipmi\").\n:param autodetect_nodegroup: (boolean) Whether or not to attempt\n nodegroup detection for this machine. The nodegroup is determined\n based on the requestor's IP address range. (if the API request\n comes from an IP range within a known nodegroup, that nodegroup\n will be used.)\n:param nodegroup: The id of the nodegroup this node belongs to.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Retrieve deployment status for multiple machines.\n\n:param machines: Mandatory list of system IDs for machines whose status\n you wish to check.\n\nReturns 400 if mandatory parameters are missing.\nReturns 403 if the user has no permission to view any of the machines.", + "method": "GET", + "name": "deployment_status", + "op": "deployment_status", + "restful": false + }, + { + "doc": "Fetch Machines that were allocated to the User/oauth token.", + "method": "GET", + "name": "list_allocated", + "op": "list_allocated", + "restful": false + }, + { + "doc": "Retrieve power parameters for multiple machines.\n\n:param id: An optional list of system ids. Only machines with\n matching system ids will be returned.\n:type id: iterable\n\n:return: A dictionary of power parameters, keyed by machine system_id.\n\nRaises 403 if the user is not an admin.", + "method": "GET", + "name": "power_parameters", + "op": "power_parameters", + "restful": false + }, + { + "doc": "List all nodes.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Release multiple machines.\n\nThis places the machines back into the pool, ready to be reallocated.\n\n:param machines: system_ids of the machines which are to be released.\n (An empty list is acceptable).\n:param comment: Optional comment for the event log.\n:type comment: unicode\n:return: The system_ids of any machines that have their status\n changed by this call. Thus, machines that were already released\n are excluded from the result.\n\nReturns 400 if any of the machines cannot be found.\nReturns 403 if the user does not have permission to release any of\nthe machines.\nReturns a 409 if any of the machines could not be released due to their\ncurrent state.", + "method": "POST", + "name": "release", + "op": "release", + "restful": false + }, + { + "doc": "Assign multiple nodes to a physical zone at once.\n\n:param zone: Zone name. If omitted, the zone is \"none\" and the nodes\n will be taken out of their physical zones.\n:param nodes: system_ids of the nodes whose zones are to be set.\n (An empty list is acceptable).\n\nRaises 403 if the user is not an admin.", + "method": "POST", + "name": "set_zone", + "op": "set_zone", + "restful": false + } + ], + "doc": "Manage the collection of all the nodes in the MAAS.", + "name": "MachinesHandler", + "params": [], + "path": "/MAAS/api/2.0/machines/", + "uri": "http://localhost:5240/MAAS/api/2.0/machines/" + }, + "name": "MachinesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Connect the given MAC addresses to this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead.", + "method": "POST", + "name": "connect_macs", + "op": "connect_macs", + "restful": false + }, + { + "doc": "Delete network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Disconnect the given MAC addresses from this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead.", + "method": "POST", + "name": "disconnect_macs", + "op": "disconnect_macs", + "restful": false + }, + { + "doc": "Returns the list of MAC addresses connected to this network.\n\nOnly MAC addresses for nodes visible to the requesting user are\nreturned.", + "method": "GET", + "name": "list_connected_macs", + "op": "list_connected_macs", + "restful": false + }, + { + "doc": "Read network definition.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead.\n\n:param name: A simple name for the network, to make it easier to\n refer to. Must consist only of letters, digits, dashes, and\n underscores.\n:param ip: Base IP address for the network, e.g. `10.1.0.0`. The host\n bits will be zeroed.\n:param netmask: Subnet mask to indicate which parts of an IP address\n are part of the network address. For example, `255.255.255.0`.\n:param vlan_tag: Optional VLAN tag: a number between 1 and 0xffe (4094)\n inclusive, or zero for an untagged network.\n:param description: Detailed description of the network for the benefit\n of users and administrators.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a network.\n\nThis endpoint is deprecated. Use the new 'subnet' endpoint instead.", + "name": "NetworkHandler", + "params": [ + "name" + ], + "path": "/MAAS/api/2.0/networks/{name}/", + "uri": "http://localhost:5240/MAAS/api/2.0/networks/{name}/" + }, + "name": "NetworkHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Define a network.\n\nThis endpoint is no longer available. Use the 'subnets' endpoint\ninstead.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List networks.\n\n:param node: Optionally, nodes which must be attached to any returned\n networks. If more than one node is given, the result will be\n restricted to networks that these nodes have in common.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the networks.\n\nThis endpoint is deprecated. Use the new 'subnets' endpoint instead.", + "name": "NetworksHandler", + "params": [], + "path": "/MAAS/api/2.0/networks/", + "uri": "http://localhost:5240/MAAS/api/2.0/networks/" + }, + "name": "NetworksHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific Node.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to delete the node.\nReturns 204 if the node is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Obtain various system details.\n\nFor example, LLDP and ``lshw`` XML dumps.\n\nReturns a ``{detail_type: xml, ...}`` map, where\n``detail_type`` is something like \"lldp\" or \"lshw\".\n\nNote that this is returned as BSON and not JSON. This is for\nefficiency, but mainly because JSON can't do binary content\nwithout applying additional encoding like base-64.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "details", + "op": "details", + "restful": false + }, + { + "doc": "Mark a node as 'broken'.\n\nIf the node is allocated, release it first.\n\n:param comment: Optional comment for the event log. Will be\n displayed on the Node as an error description until marked fixed.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nbroken.", + "method": "POST", + "name": "mark_broken", + "op": "mark_broken", + "restful": false + }, + { + "doc": "Mark a broken node as fixed and set its status as 'ready'.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nfixed.", + "method": "POST", + "name": "mark_fixed", + "op": "mark_fixed", + "restful": false + }, + { + "doc": "Read a specific Node.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": null, + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual Node.\n\nThe Node is identified by its system_id.", + "name": "NodeHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/" + }, + "name": "NodeHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Link interface to a subnet.\n\n:param mode: AUTO, DHCP, STATIC or LINK_UP connection to subnet.\n:param subnet: Subnet linked to interface.\n:param ip_address: IP address for the interface in subnet. Only used\n when mode is STATIC. If not provided an IP address from subnet\n will be auto selected.\n:param default_gateway: True sets the gateway IP address for the subnet\n as the default gateway for the node this interface belongs to.\n Option can only be used with the AUTO and STATIC modes.\n\nMode definitions:\nAUTO - Assign this interface a static IP address from the provided\nsubnet. The subnet must be a managed subnet. The IP address will\nnot be assigned until the node goes to be deployed.\n\nDHCP - Bring this interface up with DHCP on the given subnet. Only\none subnet can be set to DHCP. If the subnet is managed this\ninterface will pull from the dynamic IP range.\n\nSTATIC - Bring this interface up with a STATIC IP address on the\ngiven subnet. Any number of STATIC links can exist on an interface.\n\nLINK_UP - Bring this interface up only on the given subnet. No IP\naddress will be assigned to this interface. The interface cannot\nhave any current AUTO, DHCP or STATIC links.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "link_subnet", + "op": "link_subnet", + "restful": false + }, + { + "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Set the node to use this interface as the default gateway.\n\nIf this interface has more than one subnet with a gateway IP in the\nsame IP address family then specifying the ID of the link on\nthis interface is required.\n\n:param link_id: ID of the link on this interface to select the\n default gateway IP address from.\n\nReturns 400 if the interface has not AUTO or STATIC links.\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "set_default_gateway", + "op": "set_default_gateway", + "restful": false + }, + { + "doc": "Unlink interface to a subnet.\n\n:param id: ID of the link on the interface to remove.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "unlink_subnet", + "op": "unlink_subnet", + "restful": false + }, + { + "doc": "Update interface on node.\n\nFields for physical interface:\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to.\n\nFields for bond interface:\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parents: Parent interfaces that make this bond.\n\nFields for VLAN interface:\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFollowing are extra parameters that can be set on all interface types:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nFollowing are parameters specific to bonds:\n\n:param bond-mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond-miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond-downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond-updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond-lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond-xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n\nSupported bonding modes (bond-mode):\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nReturns 404 if the node or interface is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a node's interface. (Deprecated)", + "name": "NodeInterfaceHandler", + "params": [ + "system_id", + "interface_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/{interface_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/{interface_id}/" + }, + "name": "NodeInterfaceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a bond interface on a machine.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parents: Parent interfaces that make this bond.\n\nFollowing are parameters specific to bonds:\n\n:param bond_mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond_miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond_downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond_updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond_lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond_xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n (Default: layer2)\n\nSupported bonding modes (bond-mode):\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_bond", + "op": "create_bond", + "restful": false + }, + { + "doc": "Create a physical interface on a machine, device, or\nrack controller.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_physical", + "op": "create_physical", + "restful": false + }, + { + "doc": "Create a VLAN interface on a machine.\n\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_vlan", + "op": "create_vlan", + "restful": false + }, + { + "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage interfaces on a node. (Deprecated)", + "name": "NodeInterfacesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/" + }, + "name": "NodeInterfacesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List NodeResult visible to the user, optionally filtered.\n\n:param system_id: An optional list of system ids. Only the\n results related to the nodes with these system ids\n will be returned.\n:type system_id: iterable\n:param name: An optional list of names. Only the results\n with the specified names will be returned.\n:type name: iterable\n:param result_type: An optional result_type. Only the results\n with the specified result_type will be returned.\n:type name: iterable", + "method": "GET", + "name": "list", + "op": "list", + "restful": false + } + ], + "doc": "Read the collection of NodeResult in the MAAS.", + "name": "NodeResultsHandler", + "params": [], + "path": "/MAAS/api/2.0/installation-results/", + "uri": "http://localhost:5240/MAAS/api/2.0/installation-results/" + }, + "name": "NodeResultsHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Returns whether or not the given MAC address is registered within\nthis MAAS (and attached to a non-retired node).\n\n:param mac_address: The mac address to be checked.\n:type mac_address: unicode\n:return: 'true' or 'false'.\n:rtype: unicode\n\nReturns 400 if any mandatory parameters are missing.", + "method": "GET", + "name": "is_registered", + "op": "is_registered", + "restful": false + }, + { + "doc": null, + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Anonymous access to Nodes.", + "name": "AnonNodesHandler", + "params": [], + "path": "/MAAS/api/2.0/nodes/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/" + }, + "auth": { + "actions": [ + { + "doc": "List all nodes.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Assign multiple nodes to a physical zone at once.\n\n:param zone: Zone name. If omitted, the zone is \"none\" and the nodes\n will be taken out of their physical zones.\n:param nodes: system_ids of the nodes whose zones are to be set.\n (An empty list is acceptable).\n\nRaises 403 if the user is not an admin.", + "method": "POST", + "name": "set_zone", + "op": "set_zone", + "restful": false + } + ], + "doc": "Manage the collection of all the nodes in the MAAS.", + "name": "NodesHandler", + "params": [], + "path": "/MAAS/api/2.0/nodes/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/" + }, + "name": "NodesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete partition.\n\nReturns 404 if the node, block device, or partition are not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Format a partition.\n\n:param fstype: Type of filesystem.\n:param uuid: The UUID for the filesystem.\n:param label: The label for the filesystem.\n\nReturns 403 when the user doesn't have the ability to format the partition.\nReturns 404 if the node, block device, or partition is not found.", + "method": "POST", + "name": "format", + "op": "format", + "restful": false + }, + { + "doc": "Mount the filesystem on partition.\n\n:param mount_point: Path on the filesystem to mount.\n\nReturns 403 when the user doesn't have the ability to mount the partition.\nReturns 404 if the node, block device, or partition is not found.", + "method": "POST", + "name": "mount", + "op": "mount", + "restful": false + }, + { + "doc": "Read partition.\n\nReturns 404 if the node, block device, or partition are not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Unformat a partition.", + "method": "POST", + "name": "unformat", + "op": "unformat", + "restful": false + }, + { + "doc": "Unmount the filesystem on partition.\n\nReturns 400 if the partition is not formatted or not currently mounted.\nReturns 403 when the user doesn't have the ability to unmount the partition.\nReturns 404 if the node, block device, or partition is not found.", + "method": "POST", + "name": "unmount", + "op": "unmount", + "restful": false + } + ], + "doc": "Manage partition on a block device.", + "name": "PartitionHandler", + "params": [ + "system_id", + "device_id", + "partition_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/partition/{partition_id}", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/partition/{partition_id}" + }, + "name": "PartitionHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a partition on the block device.\n\n:param size: The size of the partition.\n:param uuid: UUID for the partition. Only used if the partition table\n type for the block device is GPT.\n:param bootable: If the partition should be marked bootable.\n\nReturns 404 if the node or the block device are not found.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all partitions on the block device.\n\nReturns 404 if the node or the block device are not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage partitions on a block device.", + "name": "PartitionsHandler", + "params": [ + "system_id", + "device_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/partitions/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/{device_id}/partitions/" + }, + "name": "PartitionsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific Node.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to delete the node.\nReturns 204 if the node is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Obtain various system details.\n\nFor example, LLDP and ``lshw`` XML dumps.\n\nReturns a ``{detail_type: xml, ...}`` map, where\n``detail_type`` is something like \"lldp\" or \"lshw\".\n\nNote that this is returned as BSON and not JSON. This is for\nefficiency, but mainly because JSON can't do binary content\nwithout applying additional encoding like base-64.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "details", + "op": "details", + "restful": false + }, + { + "doc": "Mark a node as 'broken'.\n\nIf the node is allocated, release it first.\n\n:param comment: Optional comment for the event log. Will be\n displayed on the Node as an error description until marked fixed.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nbroken.", + "method": "POST", + "name": "mark_broken", + "op": "mark_broken", + "restful": false + }, + { + "doc": "Mark a broken node as fixed and set its status as 'ready'.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nfixed.", + "method": "POST", + "name": "mark_fixed", + "op": "mark_fixed", + "restful": false + }, + { + "doc": "Read a specific Node.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Refresh the hardware information for a specific rack controller.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to refresh the rack.", + "method": "POST", + "name": "refresh", + "op": "refresh", + "restful": false + }, + { + "doc": null, + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual rack controller.\n\nThe rack controller is identified by its system_id.", + "name": "RackControllerHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/rackcontrollers/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/{system_id}/" + }, + "name": "RackControllerHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Returns whether or not the given MAC address is registered within\nthis MAAS (and attached to a non-retired node).\n\n:param mac_address: The mac address to be checked.\n:type mac_address: unicode\n:return: 'true' or 'false'.\n:rtype: unicode\n\nReturns 400 if any mandatory parameters are missing.", + "method": "GET", + "name": "is_registered", + "op": "is_registered", + "restful": false + }, + { + "doc": null, + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Anonymous access to Nodes.", + "name": "AnonNodesHandler", + "params": [], + "path": "/MAAS/api/2.0/nodes/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/" + }, + "auth": { + "actions": [ + { + "doc": "List all nodes.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Assign multiple nodes to a physical zone at once.\n\n:param zone: Zone name. If omitted, the zone is \"none\" and the nodes\n will be taken out of their physical zones.\n:param nodes: system_ids of the nodes whose zones are to be set.\n (An empty list is acceptable).\n\nRaises 403 if the user is not an admin.", + "method": "POST", + "name": "set_zone", + "op": "set_zone", + "restful": false + } + ], + "doc": "Manage the collection of all rack controllers in MAAS.", + "name": "RackControllersHandler", + "params": [], + "path": "/MAAS/api/2.0/rackcontrollers/", + "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/" + }, + "name": "RackControllersHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete RAID on node.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read RAID device on node.\n\nReturns 404 if the node or RAID is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update RAID on node.\n\n:param name: Name of the RAID.\n:param uuid: UUID of the RAID.\n:param add_block_devices: Block devices to add to the RAID.\n:param remove_block_devices: Block devices to remove from the RAID.\n:param add_spare_devices: Spare block devices to add to the RAID.\n:param remove_spare_devices: Spare block devices to remove\n from the RAID.\n:param add_partitions: Partitions to add to the RAID.\n:param remove_partitions: Partitions to remove from the RAID.\n:param add_spare_partitions: Spare partitions to add to the RAID.\n:param remove_spare_partitions: Spare partitions to remove from the\n RAID.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a specific RAID device on a node.", + "name": "RaidHandler", + "params": [ + "system_id", + "raid_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/raid/{raid_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raid/{raid_id}/" + }, + "name": "RaidHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Creates a RAID\n\n:param name: Name of the RAID.\n:param uuid: UUID of the RAID.\n:param level: RAID level.\n:param block_devices: Block devices to add to the RAID.\n:param spare_devices: Spare block devices to add to the RAID.\n:param partitions: Partitions to add to the RAID.\n:param spare_partitions: Spare partitions to add to the RAID.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all RAID devices belonging to node.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage all RAID devices on a node.", + "name": "RaidsHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/raids/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raids/" + }, + "name": "RaidsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "DELETE an SSH key.\n\nReturns 404 if the key does not exist.\nReturns 401 if the key does not belong to the calling user.", + "method": "POST", + "name": "delete", + "op": "delete", + "restful": false + }, + { + "doc": "DELETE an SSH key.\n\nReturns 404 if the key does not exist.\nReturns 401 if the key does not belong to the calling user.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "GET an SSH key.\n\nReturns 404 if the key does not exist.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage an SSH key.\n\nSSH keys can be retrieved or deleted.", + "name": "SSHKeyHandler", + "params": [ + "keyid" + ], + "path": "/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/" + }, + "name": "SSHKeyHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List all keys belonging to the requesting user.", + "method": "GET", + "name": "list", + "op": "list", + "restful": false + }, + { + "doc": "Add a new SSH key to the requesting user's account.\n\nThe request payload should contain the public SSH key data in form\ndata whose name is \"key\".", + "method": "POST", + "name": "new", + "op": "new", + "restful": false + } + ], + "doc": "Manage the collection of all the SSH keys in this MAAS.", + "name": "SSHKeysHandler", + "params": [], + "path": "/MAAS/api/2.0/account/prefs/sshkeys/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/" + }, + "name": "SSHKeysHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "DELETE an SSL key.\n\nReturns 401 if the key does not belong to the requesting user.\nReturns 204 if the key is successfully deleted.", + "method": "GET", + "name": "delete", + "op": "delete", + "restful": false + }, + { + "doc": "DELETE an SSL key.\n\nReturns 401 if the key does not belong to the requesting user.\nReturns 204 if the key is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "GET an SSL key.\n\nReturns 404 if the keyid is not found.\nReturns 401 if the key does not belong to the requesting user.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage an SSL key.\n\nSSL keys can be retrieved or deleted.", + "name": "SSLKeyHandler", + "params": [ + "keyid" + ], + "path": "/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/" + }, + "name": "SSLKeyHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List all keys belonging to the requesting user.", + "method": "GET", + "name": "list", + "op": "list", + "restful": false + }, + { + "doc": "Add a new SSL key to the requesting user's account.\n\nThe request payload should contain the SSL key data in form\ndata whose name is \"key\".", + "method": "POST", + "name": "new", + "op": "new", + "restful": false + } + ], + "doc": "Operations on multiple keys.", + "name": "SSLKeysHandler", + "params": [], + "path": "/MAAS/api/2.0/account/prefs/sslkeys/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/" + }, + "name": "SSLKeysHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete space.\n\nReturns 404 if the space is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read space.\n\nReturns 404 if the space is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update space.\n\n:param name: Name of the space.\n\nReturns 404 if the space is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage space.", + "name": "SpaceHandler", + "params": [ + "space_id" + ], + "path": "/MAAS/api/2.0/spaces/{space_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/spaces/{space_id}/" + }, + "name": "SpaceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a space.\n\n:param name: Name of the space.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all spaces.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage spaces.", + "name": "SpacesHandler", + "params": [], + "path": "/MAAS/api/2.0/spaces/", + "uri": "http://localhost:5240/MAAS/api/2.0/spaces/" + }, + "name": "SpacesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete subnet.\n\nReturns 404 if the subnet is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Returns a summary of IP addresses assigned to this subnet.\n\nOptional arguments:\nwith_username: (default=True) if False, suppresses the display\nof usernames associated with each address.\nwith_node_summary: (default=True) if False, suppresses the display\nof any node associated with each address.", + "method": "GET", + "name": "ip_addresses", + "op": "ip_addresses", + "restful": false + }, + { + "doc": "Read subnet.\n\nReturns 404 if the subnet is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Lists IP ranges currently reserved in the subnet.\n\nReturns 404 if the subnet is not found.", + "method": "GET", + "name": "reserved_ip_ranges", + "op": "reserved_ip_ranges", + "restful": false + }, + { + "doc": "Returns statistics for the specified subnet, including:\n\nnum_available - the number of available IP addresses\nlargest_available - the largest number of contiguous free IP addresses\nnum_unavailable - the number of unavailable IP addresses\ntotal_addresses - the sum of the available plus unavailable addresses\nusage - the (floating point) usage percentage of this subnet\nusage_string - the (formatted unicode) usage percentage of this subnet\nranges - the specific IP ranges present in ths subnet (if specified)\n\nOptional arguments:\ninclude_ranges: if True, includes detailed information\nabout the usage of this range.\n\nReturns 404 if the subnet is not found.", + "method": "GET", + "name": "statistics", + "op": "statistics", + "restful": false + }, + { + "doc": "Lists IP ranges currently unreserved in the subnet.\n\nReturns 404 if the subnet is not found.", + "method": "GET", + "name": "unreserved_ip_ranges", + "op": "unreserved_ip_ranges", + "restful": false + }, + { + "doc": "Update subnet.\n\n:param name: Name of the subnet.\n:param vlan: VLAN this subnet belongs to.\n:param space: Space this subnet is in.\n:param cidr: The network CIDR for this subnet.\n:param gateway_ip: The gateway IP address for this subnet.\n:param rdns_mode: How reverse DNS is handled for this subnet.\n:param dns_servers: Comma-seperated list of DNS servers for this subnet.\n\nReturns 404 if the subnet is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage subnet.", + "name": "SubnetHandler", + "params": [ + "subnet_id" + ], + "path": "/MAAS/api/2.0/subnets/{subnet_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/subnets/{subnet_id}/" + }, + "name": "SubnetHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a subnet.\n\n:param name: Name of the subnet.\n:param fabric: Fabric for the subnet. Defaults to the fabric the\n provided VLAN belongs to or defaults to the default fabric.\n:param vlan: VLAN this subnet belongs to. Defaults to the default\n VLAN for the provided fabric or defaults to the default VLAN in\n the default fabric.\n:param vid: VID of the VLAN this subnet belongs to. Only used when\n vlan is not provided. Picks the VLAN with this VID in the provided\n fabric or the default fabric if one is not given.\n:param space: Space this subnet is in. Defaults to the default space.\n:param cidr: The network CIDR for this subnet.\n:param gateway_ip: The gateway IP address for this subnet.\n:param rdns_mode: How reverse DNS is handled for this subnet.\n One of: 0 (Disabled), 1 (Enabled), or 2 (RFC2317). Disabled means\n no reverse zone is created; Enabled means generate the reverse\n zone; RFC2317 extends Enabled to create the necessary parent zone\n with the appropriate CNAME resource records for the network, if the\n network is small enough to require the support described in\n RFC2317.\n:param dns_servers: Comma-seperated list of DNS servers for this\n subnet.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all subnets.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage subnets.", + "name": "SubnetsHandler", + "params": [], + "path": "/MAAS/api/2.0/subnets/", + "uri": "http://localhost:5240/MAAS/api/2.0/subnets/" + }, + "name": "SubnetsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific Tag.\n\nReturns 404 if the tag is not found.\nReturns 204 if the tag is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Get the list of nodes that have this tag.\n\nReturns 404 if the tag is not found.", + "method": "GET", + "name": "nodes", + "op": "nodes", + "restful": false + }, + { + "doc": "Read a specific Tag.\n\nReturns 404 if the tag is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Manually trigger a rebuild the tag <=> node mapping.\n\nThis is considered a maintenance operation, which should normally not\nbe necessary. Adding nodes or updating a tag's definition should\nautomatically trigger the appropriate changes.\n\nReturns 404 if the tag is not found.", + "method": "POST", + "name": "rebuild", + "op": "rebuild", + "restful": false + }, + { + "doc": "Update a specific Tag.\n\n:param name: The name of the Tag to be created. This should be a short\n name, and will be used in the URL of the tag.\n:param comment: A long form description of what the tag is meant for.\n It is meant as a human readable description of the tag.\n:param definition: An XPATH query that will be evaluated against the\n hardware_details stored for all nodes (output of `lshw -xml`).\n\nReturns 404 if the tag is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + }, + { + "doc": "Add or remove nodes being associated with this tag.\n\n:param add: system_ids of nodes to add to this tag.\n:param remove: system_ids of nodes to remove from this tag.\n:param definition: (optional) If supplied, the definition will be\n validated against the current definition of the tag. If the value\n does not match, then the update will be dropped (assuming this was\n just a case of a worker being out-of-date)\n:param rack_controller: A system ID of a rack controller that did the\n processing. This value is optional. If not supplied, the requester\n must be a superuser. If supplied, then the requester must be the\n rack controller.\n\nReturns 404 if the tag is not found.\nReturns 401 if the user does not have permission to update the nodes.\nReturns 409 if 'definition' doesn't match the current definition.", + "method": "POST", + "name": "update_nodes", + "op": "update_nodes", + "restful": false + } + ], + "doc": "Manage a Tag.\n\nTags are properties that can be associated with a Node and serve as\ncriteria for selecting and allocating nodes.\n\nA Tag is identified by its name.", + "name": "TagHandler", + "params": [ + "name" + ], + "path": "/MAAS/api/2.0/tags/{name}/", + "uri": "http://localhost:5240/MAAS/api/2.0/tags/{name}/" + }, + "name": "TagHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List Tags.\n\nGet a listing of all tags that are currently defined.", + "method": "GET", + "name": "list", + "op": "list", + "restful": false + }, + { + "doc": "Create a new Tag.\n\n:param name: The name of the Tag to be created. This should be a short\n name, and will be used in the URL of the tag.\n:param comment: A long form description of what the tag is meant for.\n It is meant as a human readable description of the tag.\n:param definition: An XPATH query that will be evaluated against the\n hardware_details stored for all nodes (output of `lshw -xml`).\n:param kernel_opts: Can be None. If set, nodes associated with this tag\n will add this string to their kernel options when booting. The\n value overrides the global 'kernel_opts' setting. If more than one\n tag is associated with a node, the one with the lowest alphabetical\n name will be picked (eg 01-my-tag will be taken over 99-tag-name).\n\nReturns 401 if the user is not an admin.", + "method": "POST", + "name": "new", + "op": "new", + "restful": false + } + ], + "doc": "Manage the collection of all the Tags in this MAAS.", + "name": "TagsHandler", + "params": [], + "path": "/MAAS/api/2.0/tags/", + "uri": "http://localhost:5240/MAAS/api/2.0/tags/" + }, + "name": "TagsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a MAAS user account.\n\nThis is not safe: the password is sent in plaintext. Avoid it for\nproduction, unless you are confident that you can prevent eavesdroppers\nfrom observing the request.\n\n:param username: Identifier-style username for the new user.\n:type username: unicode\n:param email: Email address for the new user.\n:type email: unicode\n:param password: Password for the new user.\n:type password: unicode\n:param is_superuser: Whether the new user is to be an administrator.\n:type is_superuser: bool ('0' for False, '1' for True)\n\nReturns 400 if any mandatory parameters are missing.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List users.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the user accounts of this MAAS.", + "name": "UsersHandler", + "params": [], + "path": "/MAAS/api/2.0/users/", + "uri": "http://localhost:5240/MAAS/api/2.0/users/" + }, + "name": "UsersHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Version and capabilities of this MAAS instance.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Information about this MAAS instance.\n\nThis returns a JSON dictionary with information about this\nMAAS instance::\n\n {\n 'version': '1.8.0',\n 'subversion': 'alpha10+bzr3750',\n 'capabilities': ['capability1', 'capability2', ...]\n }", + "name": "VersionHandler", + "params": [], + "path": "/MAAS/api/2.0/version/", + "uri": "http://localhost:5240/MAAS/api/2.0/version/" + }, + "auth": null, + "name": "VersionHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN.\n\nReturns 404 if the fabric or VLAN is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage VLAN on a fabric.", + "name": "VlanHandler", + "params": [ + "fabric_id", + "vid" + ], + "path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/" + }, + "name": "VlanHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all VLANs belonging to fabric.\n\nReturns 404 if the fabric is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage VLANs on a fabric.", + "name": "VlansHandler", + "params": [ + "fabric_id" + ], + "path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/" + }, + "name": "VlansHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a logical volume in the volume group.\n\n:param name: Name of the logical volume.\n:param uuid: (optional) UUID of the logical volume.\n:param size: Size of the logical volume.\n\nReturns 404 if the node or volume group is not found.\nReturns 409 if the node is not Ready.", + "method": "POST", + "name": "create_logical_volume", + "op": "create_logical_volume", + "restful": false + }, + { + "doc": "Delete volume group on node.\n\nReturns 404 if the node or volume group is not found.\nReturns 409 if the node is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Delete a logical volume in the volume group.\n\n:param id: ID of the logical volume.\n\nReturns 403 if no logical volume with id.\nReturns 404 if the node or volume group is not found.\nReturns 409 if the node is not Ready.", + "method": "POST", + "name": "delete_logical_volume", + "op": "delete_logical_volume", + "restful": false + }, + { + "doc": "Read volume group on node.\n\nReturns 404 if the node or volume group is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Read volume group on node.\n\n:param name: Name of the volume group.\n:param uuid: UUID of the volume group.\n:param add_block_devices: Block devices to add to the volume group.\n:param remove_block_devices: Block devices to remove from the\n volume group.\n:param add_partitions: Partitions to add to the volume group.\n:param remove_partitions: Partitions to remove from the volume group.\n\nReturns 404 if the node or volume group is not found.\nReturns 409 if the node is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage volume group on a node.", + "name": "VolumeGroupHandler", + "params": [ + "system_id", + "volume_group_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/volume-group/{volume_group_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-group/{volume_group_id}/" + }, + "name": "VolumeGroupHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a volume group belonging to machine.\n\n:param name: Name of the volume group.\n:param uuid: (optional) UUID of the volume group.\n:param block_devices: Block devices to add to the volume group.\n:param partitions: Partitions to add to the volume group.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all volume groups belonging to a machine.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage volume groups on a node.", + "name": "VolumeGroupsHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/volume-groups/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-groups/" + }, + "name": "VolumeGroupsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "DELETE request. Delete zone.\n\nReturns 404 if the zone is not found.\nReturns 204 if the zone is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "GET request. Return zone.\n\nReturns 404 if the zone is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "PUT request. Update zone.\n\nReturns 404 if the zone is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a physical zone.\n\nAny node is in a physical zone, or \"zone\" for short. The meaning of a\nphysical zone is up to you: it could identify e.g. a server rack, a\nnetwork, or a data centre. Users can then allocate nodes from specific\nphysical zones, to suit their redundancy or performance requirements.\n\nThis functionality is only available to administrators. Other users can\nview physical zones, but not modify them.", + "name": "ZoneHandler", + "params": [ + "name" + ], + "path": "/MAAS/api/2.0/zones/{name}/", + "uri": "http://localhost:5240/MAAS/api/2.0/zones/{name}/" + }, + "name": "ZoneHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new physical zone.\n\n:param name: Identifier-style name for the new zone.\n:type name: unicode\n:param description: Free-form description of the new zone.\n:type description: unicode", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List zones.\n\nGet a listing of all the physical zones.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage physical zones.", + "name": "ZonesHandler", + "params": [], + "path": "/MAAS/api/2.0/zones/", + "uri": "http://localhost:5240/MAAS/api/2.0/zones/" + }, + "name": "ZonesHandler" + } + ] +} \ No newline at end of file diff --git a/maas/client/bones/tests/api20.json b/maas/client/bones/testing/api20.raw.json similarity index 100% rename from maas/client/bones/tests/api20.json rename to maas/client/bones/testing/api20.raw.json diff --git a/maas/client/bones/testing/api21.json b/maas/client/bones/testing/api21.json new file mode 100644 index 00000000..314b497f --- /dev/null +++ b/maas/client/bones/testing/api21.json @@ -0,0 +1,3270 @@ +{ + "doc": "MAAS API", + "hash": "503f93ea00f40fb77070f447466a1a557bdfd409", + "resources": [ + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create an authorisation OAuth token and OAuth consumer.\n\n:param name: Optional name of the token that will be generated.\n:type name: unicode\n:return: a json dict with four keys: 'token_key',\n 'token_secret', 'consumer_key' and 'name'(e.g.\n {token_key: 's65244576fgqs', token_secret: 'qsdfdhv34',\n consumer_key: '68543fhj854fg', name: 'MAAS consumer'}).\n:rtype: string (json)", + "method": "POST", + "name": "create_authorisation_token", + "op": "create_authorisation_token", + "restful": false + }, + { + "doc": "Delete an authorisation OAuth token and the related OAuth consumer.\n\n:param token_key: The key of the token to be deleted.\n:type token_key: unicode", + "method": "POST", + "name": "delete_authorisation_token", + "op": "delete_authorisation_token", + "restful": false + }, + { + "doc": "List authorisation tokens available to the currently logged-in user.\n\n:return: list of dictionaries representing each key's name and token.", + "method": "GET", + "name": "list_authorisation_tokens", + "op": "list_authorisation_tokens", + "restful": false + }, + { + "doc": "Modify the consumer name of an authorisation OAuth token.\n\n:param token: Can be the whole token or only the token key.\n:type token: unicode\n:param name: New name of the token.\n:type name: unicode", + "method": "POST", + "name": "update_token_name", + "op": "update_token_name", + "restful": false + } + ], + "doc": "Manage the current logged-in user.", + "name": "AccountHandler", + "params": [], + "path": "/MAAS/api/2.0/account/", + "uri": "http://localhost:5240/MAAS/api/2.0/account/" + }, + "name": "AccountHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete cache set on a machine.\n\nReturns 400 if the cache set is in use.\nReturns 404 if the machine or cache set is not found.\nReturns 409 if the machine is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read bcache cache set on a machine.\n\nReturns 404 if the machine or cache set is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Delete bcache on a machine.\n\n:param cache_device: Cache block device to replace current one.\n:param cache_partition: Cache partition to replace current one.\n\nSpecifying both a cache_device and a cache_partition is not allowed.\n\nReturns 404 if the machine or the cache set is not found.\nReturns 409 if the machine is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache cache set on a machine.", + "name": "BcacheCacheSetHandler", + "params": [ + "system_id", + "id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache-cache-set/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache-cache-set/{id}/" + }, + "name": "BcacheCacheSetHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Creates a Bcache Cache Set.\n\n:param cache_device: Cache block device.\n:param cache_partition: Cache partition.\n\nSpecifying both a cache_device and a cache_partition is not allowed.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all bcache cache sets belonging to a machine.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache cache sets on a machine.", + "name": "BcacheCacheSetsHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache-cache-sets/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache-cache-sets/" + }, + "name": "BcacheCacheSetsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete bcache on a machine.\n\nReturns 404 if the machine or bcache is not found.\nReturns 409 if the machine is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read bcache device on a machine.\n\nReturns 404 if the machine or bcache is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Delete bcache on a machine.\n\n:param name: Name of the Bcache.\n:param uuid: UUID of the Bcache.\n:param cache_set: Cache set to replace current one.\n:param backing_device: Backing block device to replace current one.\n:param backing_partition: Backing partition to replace current one.\n:param cache_mode: Cache mode (writeback, writethrough, writearound).\n\nSpecifying both a device and a partition for a given role (cache or\nbacking) is not allowed.\n\nReturns 404 if the machine or the bcache is not found.\nReturns 409 if the machine is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache device on a machine.", + "name": "BcacheHandler", + "params": [ + "system_id", + "id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcache/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcache/{id}/" + }, + "name": "BcacheHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Creates a Bcache.\n\n:param name: Name of the Bcache.\n:param uuid: UUID of the Bcache.\n:param cache_set: Cache set.\n:param backing_device: Backing block device.\n:param backing_partition: Backing partition.\n:param cache_mode: Cache mode (WRITEBACK, WRITETHROUGH, WRITEAROUND).\n\nSpecifying both a device and a partition for a given role (cache or\nbacking) is not allowed.\n\nReturns 404 if the machine is not found.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all bcache devices belonging to a machine.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage bcache devices on a machine.", + "name": "BcachesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/" + }, + "name": "BcachesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Add a tag to block device on a machine.\n\n:param tag: The tag being added.\n\nReturns 404 if the machine or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "add_tag", + "op": "add_tag", + "restful": false + }, + { + "doc": "Delete block device on a machine.\n\nReturns 404 if the machine or block device is not found.\nReturns 403 if the user is not allowed to delete the block device.\nReturns 409 if the machine is not Ready.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Format block device with filesystem.\n\n:param fstype: Type of filesystem.\n:param uuid: UUID of the filesystem.\n\nReturns 403 when the user doesn't have the ability to format the block device.\nReturns 404 if the machine or block device is not found.\nReturns 409 if the machine is not Ready or Allocated.", + "method": "POST", + "name": "format", + "op": "format", + "restful": false + }, + { + "doc": "Mount the filesystem on block device.\n\n:param mount_point: Path on the filesystem to mount.\n:param mount_options: Options to pass to mount(8).\n\nReturns 403 when the user doesn't have the ability to mount the block device.\nReturns 404 if the machine or block device is not found.\nReturns 409 if the machine is not Ready or Allocated.", + "method": "POST", + "name": "mount", + "op": "mount", + "restful": false + }, + { + "doc": "Read block device on node.\n\nReturns 404 if the machine or block device is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Remove a tag from block device on a machine.\n\n:param tag: The tag being removed.\n\nReturns 404 if the machine or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the machine is not Ready.", + "method": "POST", + "name": "remove_tag", + "op": "remove_tag", + "restful": false + }, + { + "doc": "Set this block device as the boot disk for the machine.\n\nReturns 400 if the block device is a virtual block device.\nReturns 404 if the machine or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the machine is not Ready or Allocated.", + "method": "POST", + "name": "set_boot_disk", + "op": "set_boot_disk", + "restful": false + }, + { + "doc": "Unformat block device with filesystem.\n\nReturns 400 if the block device is not formatted, currently mounted, or part of a filesystem group.\nReturns 403 when the user doesn't have the ability to unformat the block device.\nReturns 404 if the machine or block device is not found.\nReturns 409 if the machine is not Ready or Allocated.", + "method": "POST", + "name": "unformat", + "op": "unformat", + "restful": false + }, + { + "doc": "Unmount the filesystem on block device.\n\nReturns 400 if the block device is not formatted or not currently mounted.\nReturns 403 when the user doesn't have the ability to unmount the block device.\nReturns 404 if the machine or block device is not found.\nReturns 409 if the machine is not Ready or Allocated.", + "method": "POST", + "name": "unmount", + "op": "unmount", + "restful": false + }, + { + "doc": "Update block device on a machine.\n\nMachines must have a status of Ready to have access to all options.\nMachines with Deployed status can only have the name, model, serial,\nand/or id_path updated for a block device. This is intented to allow a\nbad block device to be replaced while the machine remains deployed.\n\nFields for physical block device:\n\n:param name: Name of the block device.\n:param model: Model of the block device.\n:param serial: Serial number of the block device.\n:param id_path: (optional) Only used if model and serial cannot be provided. This should be a path that is fixed and doesn't change depending on the boot order or kernel version.\n:param size: Size of the block device.\n:param block_size: Block size of the block device.\n\nFields for virtual block device:\n\n:param name: Name of the block device.\n:param uuid: UUID of the block device.\n:param size: Size of the block device. (Only allowed for logical volumes.)\n\nReturns 404 if the machine or block device is not found.\nReturns 403 if the user is not allowed to update the block device.\nReturns 409 if the machine is not Ready.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a block device on a machine.", + "name": "BlockDeviceHandler", + "params": [ + "system_id", + "id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/{id}/" + }, + "name": "BlockDeviceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a physical block device.\n\n:param name: Name of the block device.\n:param model: Model of the block device.\n:param serial: Serial number of the block device.\n:param id_path: (optional) Only used if model and serial cannot be\n provided. This should be a path that is fixed and doesn't change\n depending on the boot order or kernel version.\n:param size: Size of the block device.\n:param block_size: Block size of the block device.\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all block devices belonging to a machine.\n\nReturns 404 if the machine is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage block devices on a machine.", + "name": "BlockDevicesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/" + }, + "name": "BlockDevicesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete boot resource.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot resource.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot resource.", + "name": "BootResourceHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/boot-resources/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/" + }, + "name": "BootResourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Uploads a new boot resource.\n\n:param name: Name of the boot resource.\n:param title: Title for the boot resource.\n:param architecture: Architecture the boot resource supports.\n:param filetype: Filetype for uploaded content. (Default: tgz)\n:param content: Image content. Note: this is not a normal parameter,\n but a file upload.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Import the boot resources.", + "method": "POST", + "name": "import", + "op": "import", + "restful": false + }, + { + "doc": "Return import status.", + "method": "GET", + "name": "is_importing", + "op": "is_importing", + "restful": false + }, + { + "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Stop import of boot resources.", + "method": "POST", + "name": "stop_import", + "op": "stop_import", + "restful": false + } + ], + "doc": "Manage the boot resources.", + "name": "BootResourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/boot-resources/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/" + }, + "name": "BootResourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific boot source.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot source.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a specific boot source.\n\n:param url: The URL of the BootSource.\n:param keyring_filename: The path to the keyring file for this\n BootSource.\n:param keyring_data: The GPG keyring for this BootSource,\n base64-encoded data.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot source.", + "name": "BootSourceHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/boot-sources/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/" + }, + "name": "BootSourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific boot source.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a boot source selection.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a specific boot source selection.\n\n:param release: The release for which to import resources.\n:param arches: The list of architectures for which to import resources.\n:param subarches: The list of subarchitectures for which to import\n resources.\n:param labels: The list of labels for which to import resources.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a boot source selection.", + "name": "BootSourceSelectionHandler", + "params": [ + "boot_source_id", + "id" + ], + "path": "/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/{id}/" + }, + "name": "BootSourceSelectionHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new boot source selection.\n\n:param release: The release for which to import resources.\n:param arches: The architecture list for which to import resources.\n:param subarches: The subarchitecture list for which to import\n resources.\n:param labels: The label lists for which to import resources.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List boot source selections.\n\nGet a listing of a boot source's selections.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of boot source selections.", + "name": "BootSourceSelectionsHandler", + "params": [ + "boot_source_id" + ], + "path": "/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{boot_source_id}/selections/" + }, + "name": "BootSourceSelectionsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new boot source.\n\n:param url: The URL of the BootSource.\n:param keyring_filename: The path to the keyring file for\n this BootSource.\n:param keyring_data: The GPG keyring for this BootSource,\n base64-encoded.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List boot sources.\n\nGet a listing of boot sources.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of boot sources.", + "name": "BootSourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/boot-sources/", + "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/" + }, + "name": "BootSourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a commissioning script.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read a commissioning script.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update a commissioning script.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", + "name": "CommissioningScriptHandler", + "params": [ + "name" + ], + "path": "/MAAS/api/2.0/commissioning-scripts/{name}", + "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}" + }, + "name": "CommissioningScriptHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a new commissioning script.\n\nEach commissioning script is identified by a unique name.\n\nBy convention the name should consist of a two-digit number, a dash,\nand a brief descriptive identifier consisting only of ASCII\ncharacters. You don't need to follow this convention, but not doing\nso opens you up to risks w.r.t. encoding and ordering. The name must\nnot contain any whitespace, quotes, or apostrophes.\n\nA commissioning machine will run each of the scripts in lexicographical\norder. There are no promises about how non-ASCII characters are\nsorted, or even how upper-case letters are sorted relative to\nlower-case letters. So where ordering matters, use unique numbers.\n\nScripts built into MAAS will have names starting with \"00-maas\" or\n\"99-maas\" to ensure that they run first or last, respectively.\n\nUsually a commissioning script will be just that, a script. Ideally a\nscript should be ASCII text to avoid any confusion over encoding. But\nin some cases a commissioning script might consist of a binary tool\nprovided by a hardware vendor. Either way, the script gets passed to\nthe commissioning machine in the exact form in which it was uploaded.\n\n:param name: Unique identifying name for the script. Names should\n follow the pattern of \"25-burn-in-hard-disk\" (all ASCII, and with\n numbers greater than zero, and generally no \"weird\" characters).\n:param content: A script file, to be uploaded in binary form. Note:\n this is not a normal parameter, but a file upload. Its filename\n is ignored; MAAS will know it by the name you pass to the request.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List commissioning scripts.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", + "name": "CommissioningScriptsHandler", + "params": [], + "path": "/MAAS/api/2.0/commissioning-scripts/", + "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/" + }, + "name": "CommissioningScriptsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a DHCP snippet.\n\nReturns 404 if the DHCP snippet is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read DHCP snippet.\n\nReturns 404 if the snippet is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Revert the value of a DHCP snippet to an earlier revision.\n\n:param to: What revision in the DHCP snippet's history to revert to.\n This can either be an ID or a negative number representing how far\n back to go.\n:type to: integer\n\nReturns 404 if the DHCP snippet is not found.", + "method": "POST", + "name": "revert", + "op": "revert", + "restful": false + }, + { + "doc": "Update a DHCP snippet.\n\n:param name: The name of the DHCP snippet.\n:type name: unicode\n\n:param value: The new value of the DHCP snippet to be used in\n dhcpd.conf. Previous values are stored and can be reverted.\n:type value: unicode\n\n:param description: A description of what the DHCP snippet does.\n:type description: unicode\n\n:param enabled: Whether or not the DHCP snippet is currently enabled.\n:type enabled: boolean\n\n:param node: The node the DHCP snippet is to be used for. Can not be\n set if subnet is set.\n:type node: unicode\n\n:param subnet: The subnet the DHCP snippet is to be used for. Can not\n be set if node is set.\n:type subnet: unicode\n\n:param global_snippet: Set the DHCP snippet to be a global option. This\n removes any node or subnet links.\n:type global_snippet: boolean\n\nReturns 404 if the DHCP snippet is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual DHCP snippet.\n\nThe DHCP snippet is identified by its id.", + "name": "DHCPSnippetHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/dhcp-snippets/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/dhcp-snippets/{id}/" + }, + "name": "DHCPSnippetHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a DHCP snippet.\n\n:param name: The name of the DHCP snippet. This is required to create\n a new DHCP snippet.\n:type name: unicode\n\n:param value: The snippet of config inserted into dhcpd.conf. This is\n required to create a new DHCP snippet.\n:type value: unicode\n\n:param description: A description of what the snippet does.\n:type description: unicode\n\n:param enabled: Whether or not the snippet is currently enabled.\n:type enabled: boolean\n\n:param node: The node this snippet applies to. Cannot be used with\n subnet or global_snippet.\n:type node: unicode\n\n:param subnet: The subnet this snippet applies to. Cannot be used with\n node or global_snippet.\n:type subnet: unicode\n\n:param global_snippet: Whether or not this snippet is to be applied\n globally. Cannot be used with node or subnet.\n:type global_snippet: boolean\n\nReturns 404 if the DHCP snippet is not found.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all DHCP snippets.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of all DHCP snippets in MAAS.", + "name": "DHCPSnippetsHandler", + "params": [], + "path": "/MAAS/api/2.0/dhcp-snippets/", + "uri": "http://localhost:5240/MAAS/api/2.0/dhcp-snippets/" + }, + "name": "DHCPSnippetsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete dnsresource.\n\nReturns 403 if the user does not have permission to delete the\ndnsresource.\nReturns 404 if the dnsresource is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update dnsresource.\n\n:param fqdn: Hostname (with domain) for the dnsresource.\n:param ip_address: Address to assign to the dnsresource.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the dnsresource is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresource.", + "name": "DNSResourceHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/dnsresources/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{id}/" + }, + "name": "DNSResourceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete dnsresourcerecord.\n\nReturns 403 if the user does not have permission to delete the\ndnsresourcerecord.\nReturns 404 if the dnsresourcerecord is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update dnsresourcerecord.\n\n:param rrtype: Resource Type\n:param rrdata: Resource Data (everything to the right of Type.)\n\nReturns 403 if the user does not have permission to update the\ndnsresourcerecord.\nReturns 404 if the dnsresourcerecord is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresourcerecord.", + "name": "DNSResourceRecordHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/dnsresourcerecords/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{id}/" + }, + "name": "DNSResourceRecordHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a dnsresourcerecord.\n\n:param fqdn: Hostname (with domain) for the dnsresource. Either fqdn\n or (name, domain) must be specified. Fqdn is ignored if either\n name or domain is given.\n:param name: Hostname (without domain)\n:param domain: Domain (name or id)\n:param rrtype: resource type to create\n:param rrdata: resource data (everything to the right of\n resource type.)", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all dnsresourcerecords.\n\n:param domain: restrict the listing to entries for the domain.\n:param name: restrict the listing to entries of the given name.\n:param rrtype: restrict the listing to entries which have\n records of the given rrtype.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresourcerecords.", + "name": "DNSResourceRecordsHandler", + "params": [], + "path": "/MAAS/api/2.0/dnsresourcerecords/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/" + }, + "name": "DNSResourceRecordsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a dnsresource.\n\n:param fqdn: Hostname (with domain) for the dnsresource. Either fqdn\n or (name, domain) must be specified. Fqdn is ignored if either\n name or domain is given.\n:param name: Hostname (without domain)\n:param domain: Domain (name or id)\n:param address_ttl: Default ttl for entries in this zone.\n:param ip_addresses: (optional) Address (ip or id) to assign to the\n dnsresource.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all resources for the specified criteria.\n\n:param domain: restrict the listing to entries for the domain.\n:param name: restrict the listing to entries of the given name.\n:param rrtype: restrict the listing to entries which have\n records of the given rrtype.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage dnsresources.", + "name": "DNSResourcesHandler", + "params": [], + "path": "/MAAS/api/2.0/dnsresources/", + "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/" + }, + "name": "DNSResourcesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a specific Device.\n\nReturns 404 if the device is not found.\nReturns 403 if the user does not have permission to delete the device.\nReturns 204 if the device is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Obtain various system details.\n\nFor example, LLDP and ``lshw`` XML dumps.\n\nReturns a ``{detail_type: xml, ...}`` map, where\n``detail_type`` is something like \"lldp\" or \"lshw\".\n\nNote that this is returned as BSON and not JSON. This is for\nefficiency, but mainly because JSON can't do binary content\nwithout applying additional encoding like base-64.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "details", + "op": "details", + "restful": false + }, + { + "doc": "Obtain power parameters.\n\nThis method is reserved for admin users and returns a 403 if the\nuser is not one.\n\nThis returns the power parameters, if any, configured for a\nnode. For some types of power control this will include private\ninformation such as passwords and secret keys.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "power_parameters", + "op": "power_parameters", + "restful": false + }, + { + "doc": "Read a specific Node.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Reset a device's configuration to its initial state.\n\nReturns 404 if the device is not found.\nReturns 403 if the user does not have permission to reset the device.", + "method": "POST", + "name": "restore_default_configuration", + "op": "restore_default_configuration", + "restful": false + }, + { + "doc": "Reset a device's network options.\n\nReturns 404 if the device is not found\nReturns 403 if the user does not have permission to reset the device.", + "method": "POST", + "name": "restore_networking_configuration", + "op": "restore_networking_configuration", + "restful": false + }, + { + "doc": "Set key/value data for the current owner.\n\nPass any key/value data to this method to add, modify, or remove. A key\nis removed when the value for that key is set to an empty string.\n\nThis operation will not remove any previous keys unless explicitly\npassed with an empty string. All owner data is removed when the machine\nis no longer allocated to a user.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission.", + "method": "POST", + "name": "set_owner_data", + "op": "set_owner_data", + "restful": false + }, + { + "doc": "Update a specific device.\n\n:param hostname: The new hostname for this device.\n:type hostname: unicode\n\n:param domain: The domain for this device.\n:type domain: unicode\n\n:param parent: Optional system_id to indicate this device's parent.\n If the parent is already set and this parameter is omitted,\n the parent will be unchanged.\n:type parent: unicode\n\n:param zone: Name of a valid physical zone in which to place this\n node.\n:type zone: unicode\n\nReturns 404 if the device is not found.\nReturns 403 if the user does not have permission to update the device.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", + "name": "DeviceHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/devices/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/" + }, + "name": "DeviceHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Returns whether or not the given MAC address is registered within\nthis MAAS (and attached to a non-retired node).\n\n:param mac_address: The mac address to be checked.\n:type mac_address: unicode\n:return: 'true' or 'false'.\n:rtype: unicode\n\nReturns 400 if any mandatory parameters are missing.", + "method": "GET", + "name": "is_registered", + "op": "is_registered", + "restful": false + } + ], + "doc": "Anonymous access to Nodes.", + "name": "AnonNodesHandler", + "params": [], + "path": "/MAAS/api/2.0/nodes/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/" + }, + "auth": { + "actions": [ + { + "doc": "Create a new device.\n\n:param hostname: A hostname. If not given, one will be generated.\n:type hostname: unicode\n\n:param domain: The domain of the device. If not given the default\n domain is used.\n:type domain: unicode\n\n:param mac_addresses: One or more MAC addresses for the device.\n:type mac_addresses: unicode\n\n:param parent: The system id of the parent. Optional.\n:type parent: unicode", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List Nodes visible to the user, optionally filtered by criteria.\n\nNodes are sorted by id (i.e. most recent last) and grouped by type.\n\n:param hostname: An optional hostname. Only nodes relating to the node\n with the matching hostname will be returned. This can be specified\n multiple times to see multiple nodes.\n:type hostname: unicode\n\n:param mac_address: An optional MAC address. Only nodes relating to the\n node owning the specified MAC address will be returned. This can be\n specified multiple times to see multiple nodes.\n:type mac_address: unicode\n\n:param id: An optional list of system ids. Only nodes relating to the\n nodes with matching system ids will be returned.\n:type id: unicode\n\n:param domain: An optional name for a dns domain. Only nodes relating\n to the nodes in the domain will be returned.\n:type domain: unicode\n\n:param zone: An optional name for a physical zone. Only nodes relating\n to the nodes in the zone will be returned.\n:type zone: unicode\n\n:param agent_name: An optional agent name. Only nodes relating to the\n nodes with matching agent names will be returned.\n:type agent_name: unicode", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Assign multiple nodes to a physical zone at once.\n\n:param zone: Zone name. If omitted, the zone is \"none\" and the nodes\n will be taken out of their physical zones.\n:param nodes: system_ids of the nodes whose zones are to be set.\n (An empty list is acceptable).\n\nRaises 403 if the user is not an admin.", + "method": "POST", + "name": "set_zone", + "op": "set_zone", + "restful": false + } + ], + "doc": "Manage the collection of all the devices in the MAAS.", + "name": "DevicesHandler", + "params": [], + "path": "/MAAS/api/2.0/devices/", + "uri": "http://localhost:5240/MAAS/api/2.0/devices/" + }, + "name": "DevicesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Lists all discovered devices which have an unknown IP address.\n\nFilters the list of discovered devices by excluding any discoveries\nwhere a known MAAS node is configured with the IP address of the\ndiscovery, or has been observed using it after it was assigned by\na MAAS-managed DHCP server.\n\nDiscoveries are listed in the order they were last observed on the\nnetwork (most recent first).", + "method": "GET", + "name": "by_unknown_ip", + "op": "by_unknown_ip", + "restful": false + }, + { + "doc": "Lists all discovered devices which are completely unknown to MAAS.\n\nFilters the list of discovered devices by excluding any discoveries\nwhere a known MAAS node is configured with either the MAC address or\nthe IP address of the discovery.\n\nDiscoveries are listed in the order they were last observed on the\nnetwork (most recent first).", + "method": "GET", + "name": "by_unknown_ip_and_mac", + "op": "by_unknown_ip_and_mac", + "restful": false + }, + { + "doc": "Lists all discovered devices which have an unknown IP address.\n\nFilters the list of discovered devices by excluding any discoveries\nwhere an interface known to MAAS is configured with MAC address of the\ndiscovery.\n\nDiscoveries are listed in the order they were last observed on the\nnetwork (most recent first).", + "method": "GET", + "name": "by_unknown_mac", + "op": "by_unknown_mac", + "restful": false + }, + { + "doc": "Deletes all discovered neighbours and/or mDNS entries.\n\n:param mdns: if True, deletes all mDNS entries.\n:param neighbours: if True, deletes all neighbour entries.\n:param all: if True, deletes all discovery data.", + "method": "POST", + "name": "clear", + "op": "clear", + "restful": false + }, + { + "doc": "Lists all the devices MAAS has discovered.\n\nDiscoveries are listed in the order they were last observed on the\nnetwork (most recent first).", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Immediately run a neighbour discovery scan on all rack networks.\n\nThis command causes each connected rack controller to execute the\n'maas-rack scan-network' command, which will scan all CIDRs configured\non the rack controller using 'nmap' (if it is installed) or 'ping'.\n\nNetwork discovery must not be set to 'disabled' for this command to be\nuseful.\n\nScanning will be started in the background, and could take a long time\non rack controllers that do not have 'nmap' installed and are connected\nto large networks.\n\nIf the call is a success, this method will return a dictionary of\nresults as follows:\n\nresult: A human-readable string summarizing the results.\nscan_attempted_on: A list of rack 'system_id' values where a scan\nwas attempted. (That is, an RPC connection was successful and a\nsubsequent call was intended.)\n\nfailed_to_connect_to: A list of rack 'system_id' values where the RPC\nconnection failed.\n\nscan_started_on: A list of rack 'system_id' values where a scan was\nsuccessfully started.\n\nscan_failed_on: A list of rack 'system_id' values where\na scan was attempted, but failed because a scan was already in\nprogress.\n\nrpc_call_timed_out_on: A list of rack 'system_id' values where the\nRPC connection was made, but the call timed out before a ten second\ntimeout elapsed.\n\n:param cidr: The subnet CIDR(s) to scan (can be specified multiple\n times). If not specified, defaults to all networks.\n:param force: If True, will force the scan, even if all networks are\n specified. (This may not be the best idea, depending on acceptable\n use agreements, and the politics of the organization that owns the\n network.) Default: False.\n:param always_use_ping: If True, will force the scan to use 'ping' even\n if 'nmap' is installed. Default: False.\n:param slow: If True, and 'nmap' is being used, will limit the scan\n to nine packets per second. If the scanner is 'ping', this option\n has no effect. Default: False.\n:param threads: The number of threads to use during scanning. If 'nmap'\n is the scanner, the default is one thread per 'nmap' process. If\n 'ping' is the scanner, the default is four threads per CPU.", + "method": "POST", + "name": "scan", + "op": "scan", + "restful": false + } + ], + "doc": "Query observed discoveries.", + "name": "DiscoveriesHandler", + "params": [], + "path": "/MAAS/api/2.0/discovery/", + "uri": "http://localhost:5240/MAAS/api/2.0/discovery/" + }, + "name": "DiscoveriesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": null, + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Read or delete an observed discovery.", + "name": "DiscoveryHandler", + "params": [ + "discovery_id" + ], + "path": "/MAAS/api/2.0/discovery/{discovery_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/discovery/{discovery_id}/" + }, + "name": "DiscoveryHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete domain.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the domain is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read domain.\n\nReturns 404 if the domain is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update domain.\n\n:param name: Name of the domain.\n:param authoritative: True if we are authoritative for this domain.\n:param ttl: The default TTL for this domain.\n\nReturns 403 if the user does not have permission to update the\ndnsresource.\nReturns 404 if the domain is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage domain.", + "name": "DomainHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/domains/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/domains/{id}/" + }, + "name": "DomainHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all domains.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Set the SOA serial number (for all DNS zones.)\n\n:param serial: serial number to use next.", + "method": "POST", + "name": "set_serial", + "op": "set_serial", + "restful": false + } + ], + "doc": "Manage domains.", + "name": "DomainsHandler", + "params": [], + "path": "/MAAS/api/2.0/domains/", + "uri": "http://localhost:5240/MAAS/api/2.0/domains/" + }, + "name": "DomainsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List Node events, optionally filtered by various criteria via\nURL query parameters.\n\n:param hostname: An optional hostname. Only events relating to the node\n with the matching hostname will be returned. This can be specified\n multiple times to get events relating to more than one node.\n:param mac_address: An optional list of MAC addresses. Only\n nodes with matching MAC addresses will be returned.\n:param id: An optional list of system ids. Only nodes with\n matching system ids will be returned.\n:param zone: An optional name for a physical zone. Only nodes in the\n zone will be returned.\n:param agent_name: An optional agent name. Only nodes with\n matching agent names will be returned.\n:param level: Desired minimum log level of returned events. Returns\n this level of events and greater. Choose from: CRITICAL, DEBUG, ERROR, INFO, WARNING.\n The default is INFO.\n:param limit: Optional number of events to return. Default 100.\n Maximum: 1000.\n:param before: Optional event id. Defines where to start returning\n older events.\n:param after: Optional event id. Defines where to start returning\n newer events.", + "method": "GET", + "name": "query", + "op": "query", + "restful": false + } + ], + "doc": "Retrieve filtered node events.\n\nA specific Node's events is identified by specifying one or more\nids, hostnames, or mac addresses as a list.", + "name": "EventsHandler", + "params": [], + "path": "/MAAS/api/2.0/events/", + "uri": "http://localhost:5240/MAAS/api/2.0/events/" + }, + "name": "EventsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read fabric.\n\nReturns 404 if the fabric is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update fabric.\n\n:param name: Name of the fabric.\n:param description: Description of the fabric.\n:param class_type: Class type of the fabric.\n\nReturns 404 if the fabric is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage fabric.", + "name": "FabricHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/fabrics/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{id}/" + }, + "name": "FabricHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param description: Description of the fabric.\n:param class_type: Class type of the fabric.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all fabrics.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage fabrics.", + "name": "FabricsHandler", + "params": [], + "path": "/MAAS/api/2.0/fabrics/", + "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/" + }, + "name": "FabricsHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update fannetwork.\n\n:param name: Name of the fannetwork.\n:param overlay: Overlay network\n:param underlay: Underlay network\n:param dhcp: confiugre dhcp server for overlay net\n:param host_reserve: number of IP addresses to reserve for host\n:param bridge: override bridge name\n:param off: put this int he config, but disable it.\n\nReturns 404 if the fannetwork is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage Fan Network.", + "name": "FanNetworkHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/fannetworks/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{id}/" + }, + "name": "FanNetworkHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a fannetwork.\n\n:param name: Name of the fannetwork.\n:param overlay: Overlay network\n:param underlay: Underlay network\n:param dhcp: confiugre dhcp server for overlay net\n:param host_reserve: number of IP addresses to reserve for host\n:param bridge: override bridge name\n:param off: put this int he config, but disable it.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all fannetworks.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage Fan Networks.", + "name": "FanNetworksHandler", + "params": [], + "path": "/MAAS/api/2.0/fannetworks/", + "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/" + }, + "name": "FanNetworksHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete a FileStorage object.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", + "name": "FileHandler", + "params": [ + "filename" + ], + "path": "/MAAS/api/2.0/files/{filename}/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/" + }, + "name": "FileHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Get a file from the file storage using its key.\n\n:param key: The exact key of the file you want to get.\n:type key: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get_by_key", + "op": "get_by_key", + "restful": false + } + ], + "doc": "Anonymous file operations.\n\nThis is needed for Juju. The story goes something like this:\n\n- The Juju provider will upload a file using an \"unguessable\" name.\n\n- The name of this file (or its URL) will be shared with all the agents in\n the environment. They cannot modify the file, but they can access it\n without credentials.", + "name": "AnonFilesHandler", + "params": [], + "path": "/MAAS/api/2.0/files/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/" + }, + "auth": { + "actions": [ + { + "doc": "Add a new file to the file storage.\n\n:param filename: The file name to use in the storage.\n:type filename: string\n:param file: Actual file data with content type\n application/octet-stream\n\nReturns 400 if any of these conditions apply:\n - The filename is missing from the parameters\n - The file data is missing\n - More than one file is supplied", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Delete a FileStorage object.\n\n:param filename: The filename of the object to be deleted.\n:type filename: unicode", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Get a named file from the file storage.\n\n:param filename: The exact name of the file you want to get.\n:type filename: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get", + "op": "get", + "restful": false + }, + { + "doc": "Get a file from the file storage using its key.\n\n:param key: The exact key of the file you want to get.\n:type key: string\n:return: The file is returned in the response content.", + "method": "GET", + "name": "get_by_key", + "op": "get_by_key", + "restful": false + }, + { + "doc": "List the files from the file storage.\n\nThe returned files are ordered by file name and the content is\nexcluded.\n\n:param prefix: Optional prefix used to filter out the returned files.\n:type prefix: string", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the collection of all the files in this MAAS.", + "name": "FilesHandler", + "params": [], + "path": "/MAAS/api/2.0/files/", + "uri": "http://localhost:5240/MAAS/api/2.0/files/" + }, + "name": "FilesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "List IP addresses known to MAAS.\n\nBy default, gets a listing of all IP addresses allocated to the\nrequesting user.\n\n:param ip: If specified, will only display information for the\n specified IP address.\n:type ip: unicode (must be an IPv4 or IPv6 address)\n\nIf the requesting user is a MAAS administrator, the following options\nmay also be supplied:\n\n:param all: If True, all reserved IP addresses will be shown. (By\n default, only addresses of type 'User reserved' that are assigned\n to the requesting user are shown.)\n:type all: bool\n\n:param owner: If specified, filters the list to show only IP addresses\n owned by the specified username.\n:type user: unicode", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Release an IP address that was previously reserved by the user.\n\n:param ip: The IP address to release.\n:type ip: unicode\n\n:param force: If True, allows a MAAS administrator to force an IP\n address to be released, even if it is not a user-reserved IP\n address or does not belong to the requesting user. Use with\n caution.\n:type force: bool\n\nReturns 404 if the provided IP address is not found.", + "method": "POST", + "name": "release", + "op": "release", + "restful": false + }, + { + "doc": "Reserve an IP address for use outside of MAAS.\n\nReturns an IP adddress, which MAAS will not allow any of its known\nnodes to use; it is free for use by the requesting user until released\nby the user.\n\nThe user may supply either a subnet or a specific IP address within a\nsubnet.\n\n:param subnet: CIDR representation of the subnet on which the IP\n reservation is required. e.g. 10.1.2.0/24\n:param ip: The IP address, which must be within\n a known subnet.\n:param ip_address: (Deprecated.) Alias for 'ip' parameter. Provided\n for backward compatibility.\n:param hostname: The hostname to use for the specified IP address. If\n no domain component is given, the default domain will be used.\n:param mac: The MAC address that should be linked to this reservation.\n\nReturns 400 if there is no subnet in MAAS matching the provided one,\nor a ip_address is supplied, but a corresponding subnet\ncould not be found.\nReturns 503 if there are no more IP addresses available.", + "method": "POST", + "name": "reserve", + "op": "reserve", + "restful": false + } + ], + "doc": "Manage IP addresses allocated by MAAS.", + "name": "IPAddressesHandler", + "params": [], + "path": "/MAAS/api/2.0/ipaddresses/", + "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/" + }, + "name": "IPAddressesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete IP range.\n\nReturns 403 if not owner of IP range.\nReturns 404 if the IP range is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read IP range.\n\nReturns 404 if the IP range is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update IP range.\n\n:param start_ip: Start IP address of this range (inclusive).\n:param end_ip: End IP address of this range (inclusive).\n:param comment: A description of this range. (optional)\n\nReturns 403 if not owner of IP range.\nReturns 404 if the IP Range is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage IP range.", + "name": "IPRangeHandler", + "params": [ + "id" + ], + "path": "/MAAS/api/2.0/ipranges/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/ipranges/{id}/" + }, + "name": "IPRangeHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create an IP range.\n\n:param type: Type of this range. (`dynamic` or `reserved`)\n:param start_ip: Start IP address of this range (inclusive).\n:param end_ip: End IP address of this range (inclusive).\n:param subnet: Subnet this range is associated with. (optional)\n:param comment: A description of this range. (optional)\n\nReturns 403 if standard users tries to create a dynamic IP range.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List all IP ranges.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage IP ranges.", + "name": "IPRangesHandler", + "params": [], + "path": "/MAAS/api/2.0/ipranges/", + "uri": "http://localhost:5240/MAAS/api/2.0/ipranges/" + }, + "name": "IPRangesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Add a tag to interface on a node.\n\n:param tag: The tag being added.\n\nReturns 404 if the node or interface is not found.\nReturns 403 if the user is not allowed to update the interface.", + "method": "POST", + "name": "add_tag", + "op": "add_tag", + "restful": false + }, + { + "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Disconnect an interface.\n\nDeletes any linked subnets and IP addresses, and disconnects the\ninterface from any associated VLAN.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "disconnect", + "op": "disconnect", + "restful": false + }, + { + "doc": "Link interface to a subnet.\n\n:param mode: AUTO, DHCP, STATIC or LINK_UP connection to subnet.\n:param subnet: Subnet linked to interface.\n:param ip_address: IP address for the interface in subnet. Only used\n when mode is STATIC. If not provided an IP address from subnet\n will be auto selected.\n:param force: If True, allows LINK_UP to be set on the interface\n even if other links already exist. Also allows the selection of any\n VLAN, even a VLAN MAAS does not believe the interface to currently\n be on. Using this option will cause all other links on the\n interface to be deleted. (Defaults to False.)\n:param default_gateway: True sets the gateway IP address for the subnet\n as the default gateway for the node this interface belongs to.\n Option can only be used with the AUTO and STATIC modes.\n\nMode definitions:\nAUTO - Assign this interface a static IP address from the provided\nsubnet. The subnet must be a managed subnet. The IP address will\nnot be assigned until the node goes to be deployed.\n\nDHCP - Bring this interface up with DHCP on the given subnet. Only\none subnet can be set to DHCP. If the subnet is managed this\ninterface will pull from the dynamic IP range.\n\nSTATIC - Bring this interface up with a STATIC IP address on the\ngiven subnet. Any number of STATIC links can exist on an interface.\n\nLINK_UP - Bring this interface up only on the given subnet. No IP\naddress will be assigned to this interface. The interface cannot\nhave any current AUTO, DHCP or STATIC links.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "link_subnet", + "op": "link_subnet", + "restful": false + }, + { + "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Remove a tag from interface on a node.\n\n:param tag: The tag being removed.\n\nReturns 404 if the node or interface is not found.\nReturns 403 if the user is not allowed to update the interface.", + "method": "POST", + "name": "remove_tag", + "op": "remove_tag", + "restful": false + }, + { + "doc": "Set the node to use this interface as the default gateway.\n\nIf this interface has more than one subnet with a gateway IP in the\nsame IP address family then specifying the ID of the link on\nthis interface is required.\n\n:param link_id: ID of the link on this interface to select the\n default gateway IP address from.\n\nReturns 400 if the interface has not AUTO or STATIC links.\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "set_default_gateway", + "op": "set_default_gateway", + "restful": false + }, + { + "doc": "Unlink interface to a subnet.\n\n:param id: ID of the link on the interface to remove.\n\nReturns 404 if the node or interface is not found.", + "method": "POST", + "name": "unlink_subnet", + "op": "unlink_subnet", + "restful": false + }, + { + "doc": "Update interface on node.\n\nMachines must has status of Ready or Broken to have access to all\noptions. Machines with Deployed status can only have the name and/or\nmac_address updated for an interface. This is intented to allow a bad\ninterface to be replaced while the machine remains deployed.\n\nFields for physical interface:\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to. If not set\n then the interface is considered disconnected.\n\nFields for bond interface:\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to. If not set\n then the interface is considered disconnected.\n:param parents: Parent interfaces that make this bond.\n\nFields for VLAN interface:\n\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFields for bridge interface:\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parent: Parent interface for this bridge interface.\n\nFollowing are extra parameters that can be set on all interface types:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nFollowing are parameters specific to bonds:\n\n:param bond-mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond-miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond-downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond-updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond-lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond-xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n\nSupported bonding modes (bond-mode):\n\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nFollowing are parameters specific to bridges:\n\n:param bridge_stp: Turn spanning tree protocol on or off.\n (Default: False).\n:param bridge_fd: Set bridge forward delay to time seconds.\n (Default: 15).\n\nReturns 404 if the node or interface is not found.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a node's or device's interface.", + "name": "InterfaceHandler", + "params": [ + "system_id", + "id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/{id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/{id}/" + }, + "name": "InterfaceHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Create a bond interface on a machine.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to. If not\n provided then the interface is considered disconnected.\n:param parents: Parent interfaces that make this bond.\n\nFollowing are parameters specific to bonds:\n\n:param bond_mode: The operating mode of the bond.\n (Default: active-backup).\n:param bond_miimon: The link monitoring freqeuncy in milliseconds.\n (Default: 100).\n:param bond_downdelay: Specifies the time, in milliseconds, to wait\n before disabling a slave after a link failure has been detected.\n:param bond_updelay: Specifies the time, in milliseconds, to wait\n before enabling a slave after a link recovery has been detected.\n:param bond_lacp_rate: Option specifying the rate in which we'll ask\n our link partner to transmit LACPDU packets in 802.3ad mode.\n Available options are fast or slow. (Default: slow).\n:param bond_xmit_hash_policy: The transmit hash policy to use for\n slave selection in balance-xor, 802.3ad, and tlb modes.\n (Default: layer2)\n\nSupported bonding modes (bond-mode):\nbalance-rr - Transmit packets in sequential order from the first\navailable slave through the last. This mode provides load balancing\nand fault tolerance.\n\nactive-backup - Only one slave in the bond is active. A different\nslave becomes active if, and only if, the active slave fails. The\nbond's MAC address is externally visible on only one port (network\nadapter) to avoid confusing the switch.\n\nbalance-xor - Transmit based on the selected transmit hash policy.\nThe default policy is a simple [(source MAC address XOR'd with\ndestination MAC address XOR packet type ID) modulo slave count].\n\nbroadcast - Transmits everything on all slave interfaces. This mode\nprovides fault tolerance.\n\n802.3ad - IEEE 802.3ad Dynamic link aggregation. Creates aggregation\ngroups that share the same speed and duplex settings. Utilizes all\nslaves in the active aggregator according to the 802.3ad specification.\n\nbalance-tlb - Adaptive transmit load balancing: channel bonding that\ndoes not require any special switch support.\n\nbalance-alb - Adaptive load balancing: includes balance-tlb plus\nreceive load balancing (rlb) for IPV4 traffic, and does not require any\nspecial switch support. The receive load balancing is achieved by\nARP negotiation.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_bond", + "op": "create_bond", + "restful": false + }, + { + "doc": "Create a bridge interface on a machine.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: VLAN the interface is connected to.\n:param parent: Parent interface for this bridge interface.\n\nFollowing are parameters specific to bridges:\n\n:param bridge_stp: Turn spanning tree protocol on or off.\n (Default: False).\n:param bridge_fd: Set bridge forward delay to time seconds.\n (Default: 15).\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_bridge", + "op": "create_bridge", + "restful": false + }, + { + "doc": "Create a physical interface on a machine and device.\n\n:param name: Name of the interface.\n:param mac_address: MAC address of the interface.\n:param tags: Tags for the interface.\n:param vlan: Untagged VLAN the interface is connected to. If not\n provided then the interface is considered disconnected.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_physical", + "op": "create_physical", + "restful": false + }, + { + "doc": "Create a VLAN interface on a machine.\n\n:param tags: Tags for the interface.\n:param vlan: Tagged VLAN the interface is connected to.\n:param parent: Parent interface for this VLAN interface.\n\nFollowing are extra parameters that can be set on the interface:\n\n:param mtu: Maximum transmission unit.\n:param accept_ra: Accept router advertisements. (IPv6 only)\n:param autoconf: Perform stateless autoconfiguration. (IPv6 only)\n\nReturns 404 if the node is not found.", + "method": "POST", + "name": "create_vlan", + "op": "create_vlan", + "restful": false + }, + { + "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage interfaces on a node.", + "name": "InterfacesHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", + "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/" + }, + "name": "InterfacesHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Delete license key.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Read license key.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Update license key.\n\n:param osystem: Operating system that the key belongs to.\n:param distro_series: OS release that the key belongs to.\n:param license_key: License key for osystem/distro_series combo.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage a license key.", + "name": "LicenseKeyHandler", + "params": [ + "osystem", + "distro_series" + ], + "path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", + "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}" + }, + "name": "LicenseKeyHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Define a license key.\n\n:param osystem: Operating system that the key belongs to.\n:param distro_series: OS release that the key belongs to.\n:param license_key: License key for osystem/distro_series combo.", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "List license keys.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + } + ], + "doc": "Manage the license keys.", + "name": "LicenseKeysHandler", + "params": [], + "path": "/MAAS/api/2.0/license-keys/", + "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/" + }, + "name": "LicenseKeysHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Get a config value.\n\n:param name: The name of the config item to be retrieved.\n\nAvailable configuration items:\n\n:active_discovery_interval: Active subnet mapping interval. When enabled, each rack will scan subnets enabled for active mapping. This helps ensure discovery information is accurate and complete.\n:boot_images_auto_import: Automatically import/refresh the boot images every 60 minutes.\n:commissioning_distro_series: Default Ubuntu release used for commissioning.\n:completed_intro: Marks if the initial intro has been completed..\n:curtin_verbose: Run the fast-path installer with higher verbosity. This provides more detail in the installation logs..\n:default_distro_series: Default OS release used for deployment.\n:default_dns_ttl: Default Time-To-Live for the DNS.. If no TTL value is specified at a more specific point this is how long DNS responses are valid, in seconds.\n:default_min_hwe_kernel: Default Minimum Kernel Version. The default minimum kernel version used on all new and commissioned nodes.\n:default_osystem: Default operating system used for deployment.\n:default_storage_layout: Default storage layout. Storage layout that is applied to a node when it is commissioned. Available choices are: 'bcache' (Bcache layout), 'flat' (Flat layout), 'lvm' (LVM layout).\n:disk_erase_with_quick_erase: Use quick erase by default when erasing disks.. This is not a secure erase; it wipes only the beginning and end of each disk.\n:disk_erase_with_secure_erase: Use secure erase by default when erasing disks.. Will only be used on devices that support secure erase. Other devices will fall back to full wipe or quick erase depending on the selected options.\n:dnssec_validation: Enable DNSSEC validation of upstream zones. Only used when MAAS is running its own DNS server. This value is used as the value of 'dnssec_validation' in the DNS server config.\n:enable_analytics: Enable MAAS UI usage of Google Analytics. This helps the developers of MAAS to identify usage statistics to further development..\n:enable_disk_erasing_on_release: Erase nodes' disks prior to releasing.. Forces users to always erase disks when releasing.\n:enable_http_proxy: Enable the use of an APT and HTTP/HTTPS proxy. Provision nodes to use the built-in HTTP proxy (or user specified proxy) for APT. MAAS also uses the proxy for downloading boot images.\n:enable_third_party_drivers: Enable the installation of proprietary drivers (i.e. HPVSA).\n:http_proxy: Proxy for APT and HTTP/HTTPS. This will be passed onto provisioned nodes to use as a proxy for APT traffic. MAAS also uses the proxy for downloading boot images. If no URL is provided, the built-in MAAS proxy will be used.\n:kernel_opts: Boot parameters to pass to the kernel by default.\n:maas_name: MAAS name.\n:network_discovery: . When enabled, MAAS will use passive techniques (such as listening to ARP requests and mDNS advertisements) to observe networks attached to rack controllers. Active subnet mapping will also be available to be enabled on the configured subnets.\n:ntp_external_only: Use external NTP servers only. Configure all region controller hosts, rack controller hosts, and subsequently deployed machines to refer directly to the configured external NTP servers. Otherwise only region controller hosts will be configured to use those external NTP servers, rack contoller hosts will in turn refer to the regions' NTP servers, and deployed machines will refer to the racks' NTP servers.\n:ntp_servers: Addresses of NTP servers. NTP servers, specified as IP addresses or hostnames delimited by commas and/or spaces, to be used as time references for MAAS itself, the machines MAAS deploys, and devices that make use of MAAS's DHCP services.\n:upstream_dns: Upstream DNS used to resolve domains not managed by this MAAS (space-separated IP addresses). Only used when MAAS is running its own DNS server. This value is used as the value of 'forwarders' in the DNS server config.\n:windows_kms_host: Windows KMS activation host. FQDN or IP address of the host that provides the KMS Windows activation service. (Only needed for Windows deployments using KMS activation.)", + "method": "GET", + "name": "get_config", + "op": "get_config", + "restful": false + }, + { + "doc": "Set a config value.\n\n:param name: The name of the config item to be set.\n:param value: The value of the config item to be set.\n\nAvailable configuration items:\n\n:active_discovery_interval: Active subnet mapping interval. When enabled, each rack will scan subnets enabled for active mapping. This helps ensure discovery information is accurate and complete.\n:boot_images_auto_import: Automatically import/refresh the boot images every 60 minutes.\n:commissioning_distro_series: Default Ubuntu release used for commissioning.\n:completed_intro: Marks if the initial intro has been completed..\n:curtin_verbose: Run the fast-path installer with higher verbosity. This provides more detail in the installation logs..\n:default_distro_series: Default OS release used for deployment.\n:default_dns_ttl: Default Time-To-Live for the DNS.. If no TTL value is specified at a more specific point this is how long DNS responses are valid, in seconds.\n:default_min_hwe_kernel: Default Minimum Kernel Version. The default minimum kernel version used on all new and commissioned nodes.\n:default_osystem: Default operating system used for deployment.\n:default_storage_layout: Default storage layout. Storage layout that is applied to a node when it is commissioned. Available choices are: 'bcache' (Bcache layout), 'flat' (Flat layout), 'lvm' (LVM layout).\n:disk_erase_with_quick_erase: Use quick erase by default when erasing disks.. This is not a secure erase; it wipes only the beginning and end of each disk.\n:disk_erase_with_secure_erase: Use secure erase by default when erasing disks.. Will only be used on devices that support secure erase. Other devices will fall back to full wipe or quick erase depending on the selected options.\n:dnssec_validation: Enable DNSSEC validation of upstream zones. Only used when MAAS is running its own DNS server. This value is used as the value of 'dnssec_validation' in the DNS server config.\n:enable_analytics: Enable MAAS UI usage of Google Analytics. This helps the developers of MAAS to identify usage statistics to further development..\n:enable_disk_erasing_on_release: Erase nodes' disks prior to releasing.. Forces users to always erase disks when releasing.\n:enable_http_proxy: Enable the use of an APT and HTTP/HTTPS proxy. Provision nodes to use the built-in HTTP proxy (or user specified proxy) for APT. MAAS also uses the proxy for downloading boot images.\n:enable_third_party_drivers: Enable the installation of proprietary drivers (i.e. HPVSA).\n:http_proxy: Proxy for APT and HTTP/HTTPS. This will be passed onto provisioned nodes to use as a proxy for APT traffic. MAAS also uses the proxy for downloading boot images. If no URL is provided, the built-in MAAS proxy will be used.\n:kernel_opts: Boot parameters to pass to the kernel by default.\n:maas_name: MAAS name.\n:network_discovery: . When enabled, MAAS will use passive techniques (such as listening to ARP requests and mDNS advertisements) to observe networks attached to rack controllers. Active subnet mapping will also be available to be enabled on the configured subnets.\n:ntp_external_only: Use external NTP servers only. Configure all region controller hosts, rack controller hosts, and subsequently deployed machines to refer directly to the configured external NTP servers. Otherwise only region controller hosts will be configured to use those external NTP servers, rack contoller hosts will in turn refer to the regions' NTP servers, and deployed machines will refer to the racks' NTP servers.\n:ntp_servers: Addresses of NTP servers. NTP servers, specified as IP addresses or hostnames delimited by commas and/or spaces, to be used as time references for MAAS itself, the machines MAAS deploys, and devices that make use of MAAS's DHCP services.\n:upstream_dns: Upstream DNS used to resolve domains not managed by this MAAS (space-separated IP addresses). Only used when MAAS is running its own DNS server. This value is used as the value of 'forwarders' in the DNS server config.\n:windows_kms_host: Windows KMS activation host. FQDN or IP address of the host that provides the KMS Windows activation service. (Only needed for Windows deployments using KMS activation.)", + "method": "POST", + "name": "set_config", + "op": "set_config", + "restful": false + } + ], + "doc": "Manage the MAAS server.", + "name": "MaasHandler", + "params": [], + "path": "/MAAS/api/2.0/maas/", + "uri": "http://localhost:5240/MAAS/api/2.0/maas/" + }, + "name": "MaasHandler" + }, + { + "anon": null, + "auth": { + "actions": [ + { + "doc": "Abort a machine's current operation.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nThis currently only supports aborting of the 'Disk Erasing' operation.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to abort the\ncurrent operation.", + "method": "POST", + "name": "abort", + "op": "abort", + "restful": false + }, + { + "doc": "Clear any set default gateways on the machine.\n\nThis will clear both IPv4 and IPv6 gateways on the machine. This will\ntransition the logic of identifing the best gateway to MAAS. This logic\nis determined based the following criteria:\n\n1. Managed subnets over unmanaged subnets.\n2. Bond interfaces over physical interfaces.\n3. Machine's boot interface over all other interfaces except bonds.\n4. Physical interfaces over VLAN interfaces.\n5. Sticky IP links over user reserved IP links.\n6. User reserved IP links over auto IP links.\n\nIf the default gateways need to be specific for this machine you can\nset which interface and subnet's gateway to use when this machine is\ndeployed with the `interfaces set-default-gateway` API.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to clear the default\ngateways.", + "method": "POST", + "name": "clear_default_gateways", + "op": "clear_default_gateways", + "restful": false + }, + { + "doc": "Begin commissioning process for a machine.\n\n:param enable_ssh: Whether to enable SSH for the commissioning\n environment using the user's SSH key(s).\n:type enable_ssh: bool ('0' for False, '1' for True)\n:param skip_networking: Whether to skip re-configuring the networking\n on the machine after the commissioning has completed.\n:type skip_networking: bool ('0' for False, '1' for True)\n:param skip_storage: Whether to skip re-configuring the storage\n on the machine after the commissioning has completed.\n:type skip_storage: bool ('0' for False, '1' for True)\n\nA machine in the 'ready', 'declared' or 'failed test' state may\ninitiate a commissioning cycle where it is checked out and tested\nin preparation for transitioning to the 'ready' state. If it is\nalready in the 'ready' state this is considered a re-commissioning\nprocess which is useful if commissioning tests were changed after\nit previously commissioned.\n\nReturns 404 if the machine is not found.", + "method": "POST", + "name": "commission", + "op": "commission", + "restful": false + }, + { + "doc": "Delete a specific Node.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to delete the node.\nReturns 204 if the node is successfully deleted.", + "method": "DELETE", + "name": "delete", + "op": null, + "restful": true + }, + { + "doc": "Deploy an operating system to a machine.\n\n:param user_data: If present, this blob of user-data to be made\n available to the machines through the metadata service.\n:type user_data: base64-encoded unicode\n:param distro_series: If present, this parameter specifies the\n OS release the machine will use.\n:type distro_series: unicode\n:param hwe_kernel: If present, this parameter specified the kernel to\n be used on the machine\n:type hwe_kernel: unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nIdeally we'd have MIME multipart and content-transfer-encoding etc.\ndeal with the encapsulation of binary data, but couldn't make it work\nwith the framework in reasonable time so went for a dumb, manual\nencoding instead.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to start the machine.\nReturns 503 if the start-up attempted to allocate an IP address,\nand there were no IP addresses available on the relevant cluster\ninterface.", + "method": "POST", + "name": "deploy", + "op": "deploy", + "restful": false + }, + { + "doc": "Obtain various system details.\n\nFor example, LLDP and ``lshw`` XML dumps.\n\nReturns a ``{detail_type: xml, ...}`` map, where\n``detail_type`` is something like \"lldp\" or \"lshw\".\n\nNote that this is returned as BSON and not JSON. This is for\nefficiency, but mainly because JSON can't do binary content\nwithout applying additional encoding like base-64.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "details", + "op": "details", + "restful": false + }, + { + "doc": "Exit rescue mode process for a machine.\n\nA machine in the 'rescue mode' state may exit the rescue mode\nprocess.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to exit the\nrescue mode process for this machine.", + "method": "POST", + "name": "exit_rescue_mode", + "op": "exit_rescue_mode", + "restful": false + }, + { + "doc": "Return the rendered curtin configuration for the machine.\n\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to get the curtin\nconfiguration.", + "method": "GET", + "name": "get_curtin_config", + "op": "get_curtin_config", + "restful": false + }, + { + "doc": "Mark a node as 'broken'.\n\nIf the node is allocated, release it first.\n\n:param comment: Optional comment for the event log. Will be\n displayed on the node as an error description until marked fixed.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to mark the node\nbroken.", + "method": "POST", + "name": "mark_broken", + "op": "mark_broken", + "restful": false + }, + { + "doc": "Mark a broken node as fixed and set its status as 'ready'.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to mark the machine\nfixed.", + "method": "POST", + "name": "mark_fixed", + "op": "mark_fixed", + "restful": false + }, + { + "doc": "Mount a special-purpose filesystem, like tmpfs.\n\n:param fstype: The filesystem type. This must be a filesystem that\n does not require a block special device.\n:param mount_point: Path on the filesystem to mount.\n:param mount_option: Options to pass to mount(8).\n\nReturns 403 when the user is not permitted to mount the partition.", + "method": "POST", + "name": "mount_special", + "op": "mount_special", + "restful": false + }, + { + "doc": "Power off a node.\n\n:param stop_mode: An optional power off mode. If 'soft',\n perform a soft power down if the node's power type supports\n it, otherwise perform a hard power off. For all values other\n than 'soft', and by default, perform a hard power off. A\n soft power off generally asks the OS to shutdown the system\n gracefully before powering off, while a hard power off\n occurs immediately without any warning to the OS.\n:type stop_mode: unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to stop the node.", + "method": "POST", + "name": "power_off", + "op": "power_off", + "restful": false + }, + { + "doc": "Turn on a node.\n\n:param user_data: If present, this blob of user-data to be made\n available to the nodes through the metadata service.\n:type user_data: base64-encoded unicode\n:param comment: Optional comment for the event log.\n:type comment: unicode\n\nIdeally we'd have MIME multipart and content-transfer-encoding etc.\ndeal with the encapsulation of binary data, but couldn't make it work\nwith the framework in reasonable time so went for a dumb, manual\nencoding instead.\n\nReturns 404 if the node is not found.\nReturns 403 if the user does not have permission to start the machine.\nReturns 503 if the start-up attempted to allocate an IP address,\nand there were no IP addresses available on the relevant cluster\ninterface.", + "method": "POST", + "name": "power_on", + "op": "power_on", + "restful": false + }, + { + "doc": "Obtain power parameters.\n\nThis method is reserved for admin users and returns a 403 if the\nuser is not one.\n\nThis returns the power parameters, if any, configured for a\nnode. For some types of power control this will include private\ninformation such as passwords and secret keys.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "power_parameters", + "op": "power_parameters", + "restful": false + }, + { + "doc": "Query the power state of a node.\n\nSend a request to the node's power controller which asks it about\nthe node's state. The reply to this could be delayed by up to\n30 seconds while waiting for the power controller to respond.\nUse this method sparingly as it ties up an appserver thread\nwhile waiting.\n\n:param system_id: The node to query.\n:return: a dict whose key is \"state\" with a value of one of\n 'on' or 'off'.\n\nReturns 404 if the node is not found.\nReturns node's power state.", + "method": "GET", + "name": "query_power_state", + "op": "query_power_state", + "restful": false + }, + { + "doc": "Read a specific Node.\n\nReturns 404 if the node is not found.", + "method": "GET", + "name": "read", + "op": null, + "restful": true + }, + { + "doc": "Release a machine. Opposite of `Machines.allocate`.\n\n:param comment: Optional comment for the event log.\n:type comment: unicode\n:param erase: Erase the disk when releasing.\n:type erase: boolean\n:param secure_erase: Use the drive's secure erase feature if available.\n In some cases this can be much faster than overwriting the drive.\n Some drives implement secure erasure by overwriting themselves so\n this could still be slow.\n:type secure_erase: boolean\n:param quick_erase: Wipe 1MiB at the start and at the end of the drive\n to make data recovery inconvenient and unlikely to happen by\n accident. This is not secure.\n:type quick_erase: boolean\n\nIf neither secure_erase nor quick_erase are specified, MAAS will\noverwrite the whole disk with null bytes. This can be very slow.\n\nIf both secure_erase and quick_erase are specified and the drive does\nNOT have a secure erase feature, MAAS will behave as if only\nquick_erase was specified.\n\nIf secure_erase is specified and quick_erase is NOT specified and the\ndrive does NOT have a secure erase feature, MAAS will behave as if\nsecure_erase was NOT specified, i.e. will overwrite the whole disk\nwith null bytes. This can be very slow.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user doesn't have permission to release the machine.\nReturns 409 if the machine is in a state where it may not be released.", + "method": "POST", + "name": "release", + "op": "release", + "restful": false + }, + { + "doc": "Begin rescue mode process for a machine.\n\nA machine in the 'deployed' or 'broken' state may initiate the\nrescue mode process.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to start the\nrescue mode process for this machine.", + "method": "POST", + "name": "rescue_mode", + "op": "rescue_mode", + "restful": false + }, + { + "doc": "Reset a machine's configuration to its initial state.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to reset the machine.", + "method": "POST", + "name": "restore_default_configuration", + "op": "restore_default_configuration", + "restful": false + }, + { + "doc": "Reset a machine's networking options to its initial state.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to reset the machine.", + "method": "POST", + "name": "restore_networking_configuration", + "op": "restore_networking_configuration", + "restful": false + }, + { + "doc": "Reset a machine's storage options to its initial state.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to reset the machine.", + "method": "POST", + "name": "restore_storage_configuration", + "op": "restore_storage_configuration", + "restful": false + }, + { + "doc": "Set key/value data for the current owner.\n\nPass any key/value data to this method to add, modify, or remove. A key\nis removed when the value for that key is set to an empty string.\n\nThis operation will not remove any previous keys unless explicitly\npassed with an empty string. All owner data is removed when the machine\nis no longer allocated to a user.\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission.", + "method": "POST", + "name": "set_owner_data", + "op": "set_owner_data", + "restful": false + }, + { + "doc": "Changes the storage layout on the machine.\n\nThis can only be preformed on an allocated machine.\n\nNote: This will clear the current storage layout and any extra\nconfiguration and replace it will the new layout.\n\n:param storage_layout: Storage layout for the machine. (flat, lvm,\n and bcache)\n\nThe following are optional for all layouts:\n\n:param boot_size: Size of the boot partition.\n:param root_size: Size of the root partition.\n:param root_device: Physical block device to place the root partition.\n\nThe following are optional for LVM:\n\n:param vg_name: Name of created volume group.\n:param lv_name: Name of created logical volume.\n:param lv_size: Size of created logical volume.\n\nThe following are optional for Bcache:\n\n:param cache_device: Physical block device to use as the cache device.\n:param cache_mode: Cache mode for bcache device. (writeback,\n writethrough, writearound)\n:param cache_size: Size of the cache partition to create on the cache\n device.\n:param cache_no_part: Don't create a partition on the cache device.\n Use the entire disk as the cache device.\n\nReturns 400 if the machine is currently not allocated.\nReturns 404 if the machine could not be found.\nReturns 403 if the user does not have permission to set the storage\nlayout.", + "method": "POST", + "name": "set_storage_layout", + "op": "set_storage_layout", + "restful": false + }, + { + "doc": "Unmount a special-purpose filesystem, like tmpfs.\n\n:param mount_point: Path on the filesystem to unmount.\n\nReturns 403 when the user is not permitted to unmount the partition.", + "method": "POST", + "name": "unmount_special", + "op": "unmount_special", + "restful": false + }, + { + "doc": "Update a specific Machine.\n\n:param hostname: The new hostname for this machine.\n:type hostname: unicode\n\n:param domain: The domain for this machine. If not given the default\n domain is used.\n:type domain: unicode\n\n:param architecture: The new architecture for this machine.\n:type architecture: unicode\n\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:type min_hwe_kernel: unicode\n\n:param power_type: The new power type for this machine. If you use the\n default value, power_parameters will be set to the empty string.\n Available to admin users.\n See the `Power types`_ section for a list of the available power\n types.\n:type power_type: unicode\n\n:param power_parameters_{param1}: The new value for the 'param1'\n power parameter. Note that this is dynamic as the available\n parameters depend on the selected value of the Machine's\n power_type. Available to admin users. See the `Power types`_\n section for a list of the available power parameters for each\n power type.\n:type power_parameters_{param1}: unicode\n\n:param power_parameters_skip_check: Whether or not the new power\n parameters for this machine should be checked against the expected\n power parameters for the machine's power type ('true' or 'false').\n The default is 'false'.\n:type power_parameters_skip_check: unicode\n\n:param zone: Name of a valid physical zone in which to place this\n machine.\n:type zone: unicode\n\n:param swap_size: Specifies the size of the swap file, in bytes. Field\n accept K, M, G and T suffixes for values expressed respectively in\n kilobytes, megabytes, gigabytes and terabytes.\n:type swap_size: unicode\n\n:param disable_ipv4: Deprecated. If specified, must be False.\n:type disable_ipv4: boolean\n\n:param cpu_count: The amount of CPU cores the machine has.\n:type cpu_count: integer\n\n:param memory: How much memory the machine has.\n:type memory: unicode\n\nReturns 404 if the machine is not found.\nReturns 403 if the user does not have permission to update the machine.", + "method": "PUT", + "name": "update", + "op": null, + "restful": true + } + ], + "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", + "name": "MachineHandler", + "params": [ + "system_id" + ], + "path": "/MAAS/api/2.0/machines/{system_id}/", + "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/" + }, + "name": "MachineHandler" + }, + { + "anon": { + "actions": [ + { + "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401.", + "method": "POST", + "name": "accept", + "op": "accept", + "restful": false + }, + { + "doc": "Create a new Machine.\n\nAdding a server to a MAAS puts it on a path that will wipe its disks\nand re-install its operating system, in the event that it PXE boots.\nIn anonymous enlistment (and when the enlistment is done by a\nnon-admin), the machine is held in the \"New\" state for approval by a\nMAAS admin.\n\nThe minimum data required is:\narchitecture= (e.g. \"i386/generic\")\nmac_addresses= (e.g. \"aa:bb:cc:dd:ee:ff\")\n\n:param architecture: A string containing the architecture type of\n the machine. (For example, \"i386\", or \"amd64\".) To determine the\n supported architectures, use the boot-resources endpoint.\n:type architecture: unicode\n\n:param min_hwe_kernel: A string containing the minimum kernel version\n allowed to be ran on this machine.\n:type min_hwe_kernel: unicode\n\n:param subarchitecture: A string containing the subarchitecture type\n of the machine. (For example, \"generic\" or \"hwe-t\".) To determine\n the supported subarchitectures, use the boot-resources endpoint.\n:type subarchitecture: unicode\n\n:param mac_addresses: One or more MAC addresses for the machine. To\n specify more than one MAC address, the parameter must be specified\n twice. (such as \"machines new mac_addresses=01:02:03:04:05:06\n mac_addresses=02:03:04:05:06:07\")\n:type mac_addresses: unicode\n\n:param hostname: A hostname. If not given, one will be generated.\n:type hostname: unicode\n\n:param domain: The domain of the machine. If not given the default\n domain is used.\n:type domain: unicode\n\n:param power_type: A power management type, if applicable (e.g.\n \"virsh\", \"ipmi\").\n:type power_type:unicode\n\n:param power_parameters_{param}: The parameter(s) for the power_type.\n Note that this is dynamic as the available parameters depend on\n the selected value of the Machine's power_type. `Power types`_\n section for a list of the available power parameters for each\n power type.\n:type power_parameters_{param1}: unicode", + "method": "POST", + "name": "create", + "op": null, + "restful": true + }, + { + "doc": "Returns whether or not the given MAC address is registered within\nthis MAAS (and attached to a non-retired node).\n\n:param mac_address: The mac address to be checked.\n:type mac_address: unicode\n:return: 'true' or 'false'.\n:rtype: unicode\n\nReturns 400 if any mandatory parameters are missing.", + "method": "GET", + "name": "is_registered", + "op": "is_registered", + "restful": false + } + ], + "doc": "Anonymous access to Machines.", + "name": "AnonMachinesHandler", + "params": [], + "path": "/MAAS/api/2.0/machines/", + "uri": "http://localhost:5240/MAAS/api/2.0/machines/" + }, + "auth": { + "actions": [ + { + "doc": "Accept declared machines into the MAAS.\n\nMachines can be enlisted in the MAAS anonymously or by non-admin users,\nas opposed to by an admin. These machines are held in the New\nstate; a MAAS admin must first verify the authenticity of these\nenlistments, and accept them.\n\nEnlistments can be accepted en masse, by passing multiple machines to\nthis call. Accepting an already accepted machine is not an error, but\naccepting one that is already allocated, broken, etc. is.\n\n:param machines: system_ids of the machines whose enlistment is to be\n accepted. (An empty list is acceptable).\n:return: The system_ids of any machines that have their status changed\n by this call. Thus, machines that were already accepted are\n excluded from the result.\n\nReturns 400 if any of the machines do not exist.\nReturns 403 if the user is not an admin.", + "method": "POST", + "name": "accept", + "op": "accept", + "restful": false + }, + { + "doc": "Accept all declared machines into the MAAS.\n\nMachines can be enlisted in the MAAS anonymously or by non-admin users,\nas opposed to by an admin. These machines are held in the New\nstate; a MAAS admin must first verify the authenticity of these\nenlistments, and accept them.\n\n:return: Representations of any machines that have their status changed\n by this call. Thus, machines that were already accepted are\n excluded from the result.", + "method": "POST", + "name": "accept_all", + "op": "accept_all", + "restful": false + }, + { + "doc": "Add special hardware types.\n\n:param chassis_type: The type of hardware.\n mscm is the type for the Moonshot Chassis Manager.\n msftocs is the type for the Microsoft OCS Chassis Manager.\n powerkvm is the type for Virtual Machines on Power KVM,\n managed by Virsh.\n seamicro15k is the type for the Seamicro 1500 Chassis.\n ucsm is the type for the Cisco UCS Manager.\n virsh is the type for virtual machines managed by Virsh.\n vmware is the type for virtual machines managed by VMware.\n:type chassis_type: unicode\n\n:param hostname: The URL, hostname, or IP address to access the\n chassis.\n:type url: unicode\n\n:param username: The username used to access the chassis. This field\n is required for the seamicro15k, vmware, mscm, msftocs, and ucsm\n chassis types.\n:type username: unicode\n\n:param password: The password used to access the chassis. This field\n is required for the seamicro15k, vmware, mscm, msftocs, and ucsm\n chassis types.\n:type password: unicode\n\n:param accept_all: If true, all enlisted machines will be\n commissioned.\n:type accept_all: unicode\n\n:param rack_controller: The system_id of the rack controller to send\n the add chassis command through. If none is specifed MAAS will\n automatically determine the rack controller to use.\n:type rack_controller: unicode\n\n:param domain: The domain that each new machine added should use.\n:type domain: unicode\n\nThe following are optional if you are adding a virsh, vmware, or\npowerkvm chassis:\n\n:param prefix_filter: Filter machines with supplied prefix.\n:type prefix_filter: unicode\n\nThe following are optional if you are adding a seamicro15k chassis:\n\n:param power_control: The power_control to use, either ipmi (default),\n restapi, or restapi2.\n:type power_control: unicode\n\nThe following are optional if you are adding a vmware or msftocs\nchassis.\n\n:param port: The port to use when accessing the chassis.\n:type port: integer\n\nThe following are optioanl if you are adding a vmware chassis:\n\n:param protocol: The protocol to use when accessing the VMware\n chassis (default: https).\n:type protocol: unicode\n\n:return: A string containing the chassis powered on by which rack\n controller.\n\nReturns 404 if no rack controller can be found which has access to the\ngiven URL.\nReturns 403 if the user does not have access to the rack controller.\nReturns 400 if the required parameters were not passed.", + "method": "POST", + "name": "add_chassis", + "op": "add_chassis", + "restful": false + }, + { + "doc": "Allocate an available machine for deployment.\n\nConstraints parameters can be used to allocate a machine that possesses\ncertain characteristics. All the constraints are optional and when\nmultiple constraints are provided, they are combined using 'AND'\nsemantics.\n\n:param name: Hostname or FQDN of the desired machine. If a FQDN is\n specified, both the domain and the hostname portions must match.\n:type name: unicode\n:param system_id: system_id of the desired machine.\n:type system_id: unicode\n:param arch: Architecture of the returned machine (e.g. 'i386/generic',\n 'amd64', 'armhf/highbank', etc.).\n\n If multiple architectures are specified, the machine to acquire may\n match any of the given architectures. To request multiple\n architectures, this parameter must be repeated in the request with\n each value.\n:type arch: unicode (accepts multiple)\n:param cpu_count: Minimum number of CPUs a returned machine must have.\n\n A machine with additional CPUs may be allocated if there is no\n exact match, or if the 'mem' constraint is not also specified.\n:type cpu_count: positive integer\n:param mem: The minimum amount of memory (expressed in MB) the\n returned machine must have. A machine with additional memory may\n be allocated if there is no exact match, or the 'cpu_count'\n constraint is not also specified.\n:type mem: positive integer\n:param tags: Tags the machine must match in order to be acquired.\n\n If multiple tag names are specified, the machine must be\n tagged with all of them. To request multiple tags, this parameter\n must be repeated in the request with each value.\n:type tags: unicode (accepts multiple)\n:param not_tags: Tags the machine must NOT match.\n\n If multiple tag names are specified, the machine must NOT be\n tagged with ANY of them. To request exclusion of multiple tags,\n this parameter must be repeated in the request with each value.\n:type tags: unicode (accepts multiple)\n:param zone: Physical zone name the machine must be located in.\n:type zone: unicode\n:type not_in_zone: List of physical zones from which the machine must\n not be acquired.\n\n If multiple zones are specified, the machine must NOT be\n associated with ANY of them. To request multiple zones to\n exclude, this parameter must be repeated in the request with each\n value.\n:type not_in_zone: unicode (accepts multiple)\n:param subnets: Subnets that must be linked to the machine.\n\n \"Linked to\" means the node must be configured to acquire an address\n in the specified subnet, have a static IP address in the specified\n subnet, or have been observed to DHCP from the specified subnet\n during commissioning time (which implies that it *could* have an\n address on the specified subnet).\n\n Subnets can be specified by one of the following criteria:\n\n - : match the subnet by its 'id' field\n - fabric:: match all subnets in a given fabric.\n - ip:: Match the subnet containing with\n the with the longest-prefix match.\n - name:: Match a subnet with the given name.\n - space:: Match all subnets in a given space.\n - vid:: Match a subnet on a VLAN with the specified\n VID. Valid values range from 0 through 4094 (inclusive). An\n untagged VLAN can be specified by using the value \"0\".\n - vlan:: Match all subnets on the given VLAN.\n\n Note that (as of this writing), the 'fabric', 'space', 'vid', and\n 'vlan' specifiers are only useful for the 'not_spaces' version of\n this constraint, because they will most likely force the query\n to match ALL the subnets in each fabric, space, or VLAN, and thus\n not return any nodes. (This is not a particularly useful behavior,\n so may be changed in the future.)\n\n If multiple subnets are specified, the machine must be associated\n with all of them. To request multiple subnets, this parameter must\n be repeated in the request with each value.\n\n Note that this replaces the leagcy 'networks' constraint in MAAS\n 1.x.\n:type subnets: unicode (accepts multiple)\n:param not_subnets: Subnets that must NOT be linked to the machine.\n\n See the 'subnets' constraint documentation above for more\n information about how each subnet can be specified.\n\n If multiple subnets are specified, the machine must NOT be\n associated with ANY of them. To request multiple subnets to\n exclude, this parameter must be repeated in the request with each\n value. (Or a fabric, space, or VLAN specifier may be used to match\n multiple subnets).\n\n Note that this replaces the leagcy 'not_networks' constraint in\n MAAS 1.x.\n:type not_subnets: unicode (accepts multiple)\n:param storage: A list of storage constraint identifiers, in the form:\n