From 6340be6152eeb007f31006bb0b78f2673da1a60b Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Fri, 17 Feb 2017 18:08:36 +0100 Subject: [PATCH 001/245] Make Origin.connect and .login available at maas.client. --- maas/client/__init__.py | 46 ++++++++++++++++++++++++++++++++ maas/client/tests/test_client.py | 45 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 maas/client/tests/test_client.py diff --git a/maas/client/__init__.py b/maas/client/__init__.py index e69de29..1aa0dbd 100644 --- a/maas/client/__init__.py +++ b/maas/client/__init__.py @@ -0,0 +1,46 @@ +"""Basic entry points.""" + +import threading as _threading + + +def _connect(url, *, apikey=None, insecure=False): + """Make an `Origin` by connecting with an apikey. + + :return: A tuple of ``profile`` and ``origin``, where the former is an + unsaved `Profile` instance, and the latter is an `Origin` instance + made using the profile. + """ + _load() + return connect(url, apikey=apikey, insecure=insecure) + + +def _login(url, *, username=None, password=None, insecure=False): + """Make an `Origin` by logging-in with a username and password. + + :return: A tuple of ``profile`` and ``origin``, where the former is an + unsaved `Profile` instance, and the latter is an `Origin` instance + made using the profile. + """ + _load() + return login(url, username=username, password=password, insecure=insecure) + + +# Begin with stubs. We keep the stubs in _connect and _login for run-time +# reference, for the curious, but also for testing, where we verify that the +# stubs' signatures perfectly match those of the concrete implementation. +connect = _connect +login = _login + + +# Paranoia, belt-n-braces, call it what you will: replace the stubs only when +# holding this lock, just in case. +_load_lock = _threading.RLock() + + +def _load(): + """Replace stubs with concrete implementations.""" + global connect, login + with _load_lock: + from .viscera import Origin + connect = Origin.connect + login = Origin.login diff --git a/maas/client/tests/test_client.py b/maas/client/tests/test_client.py new file mode 100644 index 0000000..e35bc7f --- /dev/null +++ b/maas/client/tests/test_client.py @@ -0,0 +1,45 @@ +"""Tests for `maas.client`.""" + +__all__ = [] + +from inspect import ( + getdoc, + signature, +) + +from testtools.matchers import ( + Equals, + Is, + Not, +) + +from ... import client +from ..testing import TestCase +from ..viscera import Origin + + +class TestStubs(TestCase): + """Tests that stubs match their concrete counterparts.""" + + def setUp(self): + super(TestStubs, self).setUp() + client._load() # Ensure the stubs have been replaced. + + def test__connect_stub_matches_Origin_connect(self): + stub, real = client._connect, client.connect + self.assertThat(real, Equals(Origin.connect)) + self.assertSignaturesAndDocsMatch(stub, real) + + def test__login_stub_matches_Origin_login(self): + stub, real = client._login, client.login + self.assertThat(real, Equals(Origin.login)) + self.assertSignaturesAndDocsMatch(stub, real) + + def assertSignaturesAndDocsMatch(self, stub, real): + self.assertThat(stub, Not(Is(real))) + sig_stub = signature(client._connect) + sig_real = signature(client.connect) + self.assertThat(sig_stub, Equals(sig_real)) + doc_real = getdoc(real) + doc_stub = getdoc(stub) + self.assertThat(doc_stub, Equals(doc_real)) From c5ec6bbe456a2a63f727e272a4840abe171869ac Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 15:21:20 +0100 Subject: [PATCH 002/245] Fix (and test) fetch_api_description. --- maas/client/utils/__init__.py | 6 ++++-- maas/client/utils/tests/test_utils.py | 31 ++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/maas/client/utils/__init__.py b/maas/client/utils/__init__.py index cc1fac7..9b9ac4e 100644 --- a/maas/client/utils/__init__.py +++ b/maas/client/utils/__init__.py @@ -38,6 +38,7 @@ from oauthlib import oauth1 +from .async import asynchronous from .creds import Credentials from .multipart import ( build_multipart_message, @@ -336,12 +337,13 @@ def __exit__(self, *exc_info): @typed -def fetch_api_description( +@asynchronous +async def fetch_api_description( url: ParseResult, credentials: Optional[Credentials], insecure: bool): """Fetch the API description from the remote MAAS instance.""" # Circular import. from .. import bones - session = bones.SessionAPI.fromURL( + session = await bones.SessionAPI.fromURL( url.geturl(), credentials=credentials, insecure=insecure) return session.description diff --git a/maas/client/utils/tests/test_utils.py b/maas/client/utils/tests/test_utils.py index cec095d..b9f2215 100644 --- a/maas/client/utils/tests/test_utils.py +++ b/maas/client/utils/tests/test_utils.py @@ -7,21 +7,30 @@ from itertools import cycle import os import os.path +import random from unittest.mock import sentinel +from urllib.parse import urlparse from testtools.matchers import ( AfterPreprocessing, Equals, + Is, MatchesListwise, ) from twisted.internet.task import Clock -from ... import utils +from ... import ( + bones, + utils, +) from ...testing import ( + make_name, make_name_without_spaces, make_string, TestCase, ) +from ...viscera.testing import AsyncMock +from ..creds import Credentials class TestMAASOAuth(TestCase): @@ -430,3 +439,23 @@ def test_intervals_can_be_an_iterable(self): self.assertRetry(clock, next(gen_retries), 103.5, -98.5, 0.0) # All done. self.assertRaises(StopIteration, next, gen_retries) + + +class TestFetchAPIDescription(TestCase): + """Tests for `fetch_api_description`.""" + + def test__calls_through_to_SessionAPI(self): + fromURL = self.patch(bones.SessionAPI, "fromURL", AsyncMock()) + fromURL.return_value.description = sentinel.description + + url = urlparse("http://maas.example.com:5420/MAAS/") + credentials = Credentials( + make_name('consumer_key'), make_name('token_key'), + make_name('secret_key')) + insecure = random.choice((True, False)) + + self.assertThat( + utils.fetch_api_description(url, credentials, insecure), + Is(sentinel.description)) + fromURL.assert_called_once_with( + url.geturl(), credentials=credentials, insecure=insecure) From ae84d2e5d61e850e68df6746f7407ab491eab21c Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 15:22:45 +0100 Subject: [PATCH 003/245] =?UTF-8?q?Client=20fa=C3=A7ades.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maas/client/_client.py | 86 +++++++++++++++++++++++++++++++ maas/client/tests/test__client.py | 62 ++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 maas/client/_client.py create mode 100644 maas/client/tests/test__client.py diff --git a/maas/client/_client.py b/maas/client/_client.py new file mode 100644 index 0000000..1b7dd6c --- /dev/null +++ b/maas/client/_client.py @@ -0,0 +1,86 @@ +"""Client façade.""" + +from functools import update_wrapper + + +class Façade: + """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 façade class allows us to + present that commingled namespace without coding it as such. + """ + + def __init__(self, client, name, methods): + super(Façade, 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 FaçadeDescriptor: + """Lazily create a façade 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(FaçadeDescriptor, self).__init__() + self.name, self.factory = name, factory + + def __get__(self, obj, typ=None): + methods = self.factory(obj._origin) + façade = Façade(obj, self.name, methods) + obj.__dict__[self.name] = façade + return façade + + +def façade(factory): + """Declare a method as a façade factory.""" + wrapper = FaçadeDescriptor(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 + + @façade + def machines(origin): + return { + "allocate": origin.Machines.allocate, + "get": origin.Machine.read, + "list": origin.Machines.read, + } + + @façade + def devices(origin): + return { + "get": origin.Device.read, + "list": origin.Devices.read, + } diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test__client.py new file mode 100644 index 0000000..20dd489 --- /dev/null +++ b/maas/client/tests/test__client.py @@ -0,0 +1,62 @@ +"""Tests for `maas.client._client`.""" + +__all__ = [] + +from unittest.mock import Mock + +from testtools.matchers import ( + IsInstance, + MatchesAll, + MatchesStructure, +) + +from .. import ( + _client, + viscera, +) +from ..testing import TestCase + + +class TestClient(TestCase): + """Tests for the simplified client.""" + + def setUp(self): + super(TestClient, self).setUp() + self.session = Mock(name="session", handlers={}) + self.origin = viscera.Origin(self.session) + self.client = _client.Client(self.origin) + + def test__client_maps_devices(self): + self.assertThat(self.client, MatchesClient( + devices=MatchesFaçade( + get=self.origin.Device.read, + list=self.origin.Devices.read, + ), + )) + + def test__client_maps_machines(self): + self.assertThat(self.client, MatchesClient( + machines=MatchesFaçade( + allocate=self.origin.Machines.allocate, + get=self.origin.Machine.read, + list=self.origin.Machines.read, + ), + )) + + +def MatchesClient(**façades): + """Matches a `_client.Client` with the given façades.""" + return MatchesAll( + IsInstance(_client.Client), + MatchesStructure(**façades), + first_only=True, + ) + + +def MatchesFaçade(**methods): + """Matches a `_client.Façade` with the given methods.""" + return MatchesAll( + IsInstance(_client.Façade), + MatchesStructure.byEquality(**methods), + first_only=True, + ) From 823cdcf2a2efc417f3a0752b126ed619faa2a9e0 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 15:23:48 +0100 Subject: [PATCH 004/245] =?UTF-8?q?Switch=20to=20using=20the=20new=20clien?= =?UTF-8?q?t=20fa=C3=A7ades.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maas/client/__init__.py | 59 ++++++++++++---------------- maas/client/tests/test_client.py | 67 +++++++++++++++++++------------- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/maas/client/__init__.py b/maas/client/__init__.py index 1aa0dbd..55532e1 100644 --- a/maas/client/__init__.py +++ b/maas/client/__init__.py @@ -1,46 +1,35 @@ """Basic entry points.""" -import threading as _threading +from . import _client -def _connect(url, *, apikey=None, insecure=False): - """Make an `Origin` by connecting with an apikey. +def connect(url, *, apikey=None, insecure=False): + """Connect to MAAS at `url` using a previously obtained API key. - :return: A tuple of ``profile`` and ``origin``, where the former is an - unsaved `Profile` instance, and the latter is an `Origin` instance - made using the profile. - """ - _load() - return connect(url, apikey=apikey, insecure=insecure) - - -def _login(url, *, username=None, password=None, insecure=False): - """Make an `Origin` by logging-in with a username and password. + :param url: The URL of MAAS, e.g. http://maas.example.com:5240/MAAS/ + :param apikey: The API key to use, e.g. + SkTvsyHhzkREvvdtNk:Ywn5FvXVupVPvNUhrN:cm3Q2f5naXYPYsrPDPfQy9Q9cUFaEgbM + :param insecure: Whether to check TLS certificates when using HTTPS. - :return: A tuple of ``profile`` and ``origin``, where the former is an - unsaved `Profile` instance, and the latter is an `Origin` instance - made using the profile. + :return: A client object. """ - _load() - return login(url, username=username, password=password, insecure=insecure) + from .viscera import Origin # Lazy. + profile, origin = Origin.connect( + url, apikey=apikey, insecure=insecure) + return _client.Client(origin) -# Begin with stubs. We keep the stubs in _connect and _login for run-time -# reference, for the curious, but also for testing, where we verify that the -# stubs' signatures perfectly match those of the concrete implementation. -connect = _connect -login = _login +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/ + :param username: The user name to use, e.g. fred. + :param password: The user's password. + :param insecure: Whether to check TLS certificates when using HTTPS. -# Paranoia, belt-n-braces, call it what you will: replace the stubs only when -# holding this lock, just in case. -_load_lock = _threading.RLock() - - -def _load(): - """Replace stubs with concrete implementations.""" - global connect, login - with _load_lock: - from .viscera import Origin - connect = Origin.connect - login = Origin.login + :return: A client object. + """ + from .viscera import Origin # Lazy. + profile, origin = Origin.login( + url, username=username, password=password, insecure=insecure) + return _client.Client(origin) diff --git a/maas/client/tests/test_client.py b/maas/client/tests/test_client.py index e35bc7f..d37e3b2 100644 --- a/maas/client/tests/test_client.py +++ b/maas/client/tests/test_client.py @@ -2,44 +2,57 @@ __all__ = [] -from inspect import ( - getdoc, - signature, -) +from inspect import signature +from unittest.mock import sentinel from testtools.matchers import ( Equals, Is, + IsInstance, Not, ) +from .. import _client from ... import client from ..testing import TestCase from ..viscera import Origin -class TestStubs(TestCase): - """Tests that stubs match their concrete counterparts.""" - - def setUp(self): - super(TestStubs, self).setUp() - client._load() # Ensure the stubs have been replaced. - - def test__connect_stub_matches_Origin_connect(self): - stub, real = client._connect, client.connect - self.assertThat(real, Equals(Origin.connect)) - self.assertSignaturesAndDocsMatch(stub, real) - - def test__login_stub_matches_Origin_login(self): - stub, real = client._login, client.login - self.assertThat(real, Equals(Origin.login)) - self.assertSignaturesAndDocsMatch(stub, real) - - def assertSignaturesAndDocsMatch(self, stub, real): +class TestFunctions(TestCase): + """Tests for module functions.""" + + def test__connect_matches_Origin_connect(self): + stub, real = client.connect, Origin.connect + self.assertSignaturesMatch(stub, real) + + def test__connect_calls_through_to_Origin(self): + connect = self.patch(Origin, "connect") + connect.return_value = sentinel.profile, sentinel.origin + client_object = client.connect( + sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) + connect.assert_called_once_with( + sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) + self.assertThat(client_object, IsInstance(_client.Client)) + self.assertThat(client_object._origin, Is(sentinel.origin)) + + def test__login_matches_Origin_login(self): + stub, real = client.login, Origin.login + self.assertSignaturesMatch(stub, real) + + def test__login_calls_through_to_Origin(self): + login = self.patch(Origin, "login") + login.return_value = sentinel.profile, sentinel.origin + client_object = client.login( + sentinel.url, username=sentinel.username, + password=sentinel.password, insecure=sentinel.insecure) + login.assert_called_once_with( + sentinel.url, username=sentinel.username, + password=sentinel.password, insecure=sentinel.insecure) + self.assertThat(client_object, IsInstance(_client.Client)) + self.assertThat(client_object._origin, Is(sentinel.origin)) + + def assertSignaturesMatch(self, stub, real): self.assertThat(stub, Not(Is(real))) - sig_stub = signature(client._connect) - sig_real = signature(client.connect) + sig_stub = signature(client.connect) + sig_real = signature(Origin.connect) self.assertThat(sig_stub, Equals(sig_real)) - doc_real = getdoc(real) - doc_stub = getdoc(stub) - self.assertThat(doc_stub, Equals(doc_real)) From 0f3aeff6539774b690c0ddefed2b004e130d41d4 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 21 Feb 2017 10:00:08 +0100 Subject: [PATCH 005/245] =?UTF-8?q?Change=20fa=C3=A7ade=20to=20facade=20ev?= =?UTF-8?q?erywhere.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- maas/client/_client.py | 30 +++++++++++++++--------------- maas/client/tests/test__client.py | 16 ++++++++-------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/maas/client/_client.py b/maas/client/_client.py index 1b7dd6c..8b84340 100644 --- a/maas/client/_client.py +++ b/maas/client/_client.py @@ -1,9 +1,9 @@ -"""Client façade.""" +"""Client facade.""" from functools import update_wrapper -class Façade: +class Facade: """Present a simplified API for interacting with MAAS. The viscera API separates set-based interactions from those on individual @@ -13,12 +13,12 @@ class Façade: 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 façade class allows us to + 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(Façade, self).__init__() + super(Facade, self).__init__() self._client = client self._name = name self._populate(methods) @@ -31,8 +31,8 @@ def __repr__(self): return "<%s>" % self._name -class FaçadeDescriptor: - """Lazily create a façade on first use. +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 @@ -47,19 +47,19 @@ class FaçadeDescriptor: """ def __init__(self, name, factory): - super(FaçadeDescriptor, self).__init__() + super(FacadeDescriptor, self).__init__() self.name, self.factory = name, factory def __get__(self, obj, typ=None): methods = self.factory(obj._origin) - façade = Façade(obj, self.name, methods) - obj.__dict__[self.name] = façade - return façade + facade = Facade(obj, self.name, methods) + obj.__dict__[self.name] = facade + return facade -def façade(factory): - """Declare a method as a façade factory.""" - wrapper = FaçadeDescriptor(factory.__name__, factory) +def facade(factory): + """Declare a method as a facade factory.""" + wrapper = FacadeDescriptor(factory.__name__, factory) return update_wrapper(wrapper, factory) @@ -70,7 +70,7 @@ def __init__(self, origin): super(Client, self).__init__() self._origin = origin - @façade + @facade def machines(origin): return { "allocate": origin.Machines.allocate, @@ -78,7 +78,7 @@ def machines(origin): "list": origin.Machines.read, } - @façade + @facade def devices(origin): return { "get": origin.Device.read, diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test__client.py index 20dd489..3fd0950 100644 --- a/maas/client/tests/test__client.py +++ b/maas/client/tests/test__client.py @@ -28,7 +28,7 @@ def setUp(self): def test__client_maps_devices(self): self.assertThat(self.client, MatchesClient( - devices=MatchesFaçade( + devices=MatchesFacade( get=self.origin.Device.read, list=self.origin.Devices.read, ), @@ -36,7 +36,7 @@ def test__client_maps_devices(self): def test__client_maps_machines(self): self.assertThat(self.client, MatchesClient( - machines=MatchesFaçade( + machines=MatchesFacade( allocate=self.origin.Machines.allocate, get=self.origin.Machine.read, list=self.origin.Machines.read, @@ -44,19 +44,19 @@ def test__client_maps_machines(self): )) -def MatchesClient(**façades): - """Matches a `_client.Client` with the given façades.""" +def MatchesClient(**facades): + """Matches a `_client.Client` with the given facades.""" return MatchesAll( IsInstance(_client.Client), - MatchesStructure(**façades), + MatchesStructure(**facades), first_only=True, ) -def MatchesFaçade(**methods): - """Matches a `_client.Façade` with the given methods.""" +def MatchesFacade(**methods): + """Matches a `_client.Facade` with the given methods.""" return MatchesAll( - IsInstance(_client.Façade), + IsInstance(_client.Facade), MatchesStructure.byEquality(**methods), first_only=True, ) From 5265487f9edd7c4b6543fad30143fa4ddfe956d0 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 15:34:42 +0100 Subject: [PATCH 006/245] Get login working again. --- maas/client/utils/auth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maas/client/utils/auth.py b/maas/client/utils/auth.py index 1b6c81b..36d07b4 100644 --- a/maas/client/utils/auth.py +++ b/maas/client/utils/auth.py @@ -67,7 +67,7 @@ def obtain_token(url, username, password, *, insecure=False): # Extract the CSRF token. login_doc = bs4.BeautifulSoup(response.content, "html.parser") - login_button = login_doc.find('input', value="Login") + login_button = login_doc.find('button', text="Login") login_form = login_button.findParent("form") login_data = { elem["name"]: elem["value"] for elem in login_form("input") @@ -77,7 +77,7 @@ def obtain_token(url, username, password, *, insecure=False): login_data["password"] = password # The following `requester` field is not used (at the time of # writing) but it ought to be associated with this new token so - # that tokens can be selectively revoked a later date. + # that tokens can be selectively revoked at a later date. login_data["requester"] = "%s@%s" % (getuser(), gethostname()) # Log-in to MAAS. From 87697050e740b3dcd3bcca0d88381fc3a3802d14 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 16:21:04 +0100 Subject: [PATCH 007/245] Implement equality checking for Object and ObjectSet. --- maas/client/viscera/__init__.py | 16 ++++++++++++ maas/client/viscera/tests/test_viscera.py | 31 +++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/maas/client/viscera/__init__.py b/maas/client/viscera/__init__.py index 74546ca..b2e2833 100644 --- a/maas/client/viscera/__init__.py +++ b/maas/client/viscera/__init__.py @@ -196,6 +196,14 @@ def __init__(self, data, local_data=None): "local_data must be a mapping, not %s" % type(data).__name__) + def __eq__(self, other): + """Strict equality check. + + The type of `other` must exactly match the type of `self`. All data + must also match. + """ + return type(self) is type(other) and self._data == other._data + def __repr__(self, *, name=None, fields=None): if name is None: name = self.__class__.__name__ @@ -274,6 +282,14 @@ def __contains__(self, item): """ return item in self._items + def __eq__(self, other): + """Strict equality check. + + The type of `other` must exactly match the type of `self`. All items + must also match. + """ + return type(self) is type(other) and self._items == other._items + def __repr__(self): return "<%s length=%d items=%r>" % ( self.__class__.__name__, len(self._items), self._items) diff --git a/maas/client/viscera/tests/test_viscera.py b/maas/client/viscera/tests/test_viscera.py index 733d873..b6fc1df 100644 --- a/maas/client/viscera/tests/test_viscera.py +++ b/maas/client/viscera/tests/test_viscera.py @@ -33,6 +33,7 @@ viscera, ) from ...testing import ( + make_name, make_name_without_spaces, TestCase, ) @@ -272,6 +273,21 @@ def test__init_insists_on_mapping(self): error = self.assertRaises(TypeError, Object, ["some", "items"]) self.assertThat(str(error), Equals("data must be a mapping, not list")) + def test__equal_when_data_matches(self): + data = {"key": make_name("value")} + object_a = Object(data) + object_b = Object(data) + self.assertThat(object_a, Equals(object_b)) + self.assertThat(object_b, Equals(object_a)) + + def test__not_equal_when_types_different(self): + # Even if one is a subclass of the other. + data = {"key": make_name("value")} + object_a = Object(data) + object_b = type("Object", (Object,), {})(data) + self.assertThat(object_a, Not(Equals(object_b))) + self.assertThat(object_b, Not(Equals(object_a))) + def test__string_representation_includes_field_values(self): class Example(Object): @@ -382,6 +398,21 @@ def test__membership_can_be_tested(self): self.assertThat(objectset, Contains(item1)) self.assertThat(objectset, Not(Contains(item2))) + def test__equal_when_items_match(self): + items = [{"key": make_name("value")}] + objectset_a = ObjectSet(items) + objectset_b = ObjectSet(items) + self.assertThat(objectset_a, Equals(objectset_b)) + self.assertThat(objectset_b, Equals(objectset_a)) + + def test__not_equal_when_types_different(self): + # Even if one is a subclass of the other. + items = [{"key": make_name("value")}] + objectset_a = ObjectSet(items) + objectset_b = type("ObjectSet", (ObjectSet,), {})(items) + self.assertThat(objectset_a, Not(Equals(objectset_b))) + self.assertThat(objectset_b, Not(Equals(objectset_a))) + def test__string_representation_includes_length_and_items(self): class Example(Object): From b4f2fc0dace20846703396163e0d26b4dd895e46 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 16:22:11 +0100 Subject: [PATCH 008/245] Fix and test Device and Devices in viscera. --- maas/client/viscera/devices.py | 4 +- maas/client/viscera/tests/test_devices.py | 59 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 maas/client/viscera/tests/test_devices.py diff --git a/maas/client/viscera/devices.py b/maas/client/viscera/devices.py index 0951c0c..c9367b4 100644 --- a/maas/client/viscera/devices.py +++ b/maas/client/viscera/devices.py @@ -35,8 +35,8 @@ class Devices(ObjectSet, metaclass=DevicesType): class DeviceType(ObjectType): - def read(cls, system_id): - data = cls._handler.read(system_id=system_id) + async def read(cls, system_id): + data = await cls._handler.read(system_id=system_id) return cls(data) diff --git a/maas/client/viscera/tests/test_devices.py b/maas/client/viscera/tests/test_devices.py new file mode 100644 index 0000000..32994f3 --- /dev/null +++ b/maas/client/viscera/tests/test_devices.py @@ -0,0 +1,59 @@ +"""Test for `maas.client.viscera.devices`.""" + +__all__ = [] + +from testtools.matchers import Equals + +from .. import devices +from ...testing import ( + make_name_without_spaces, + TestCase, +) +from ..testing import bind + + +def make_origin(): + # Create a new origin with Devices and Device. The former refers to the + # latter via the origin, hence why it must be bound. + return bind(devices.Devices, devices.Device) + + +class TestDevice(TestCase): + + def test__string_representation_includes_only_system_id_and_hostname(self): + device = devices.Device({ + "system_id": make_name_without_spaces("system-id"), + "hostname": make_name_without_spaces("hostname"), + }) + self.assertThat(repr(device), Equals( + "" + % device._data)) + + def test__read(self): + data = { + "system_id": make_name_without_spaces("system-id"), + "hostname": make_name_without_spaces("hostname"), + } + + origin = make_origin() + origin.Device._handler.read.return_value = data + + device_observed = origin.Device.read(data["system_id"]) + device_expected = origin.Device(data) + self.assertThat(device_observed, Equals(device_expected)) + + +class TestDevices(TestCase): + + def test__read(self): + data = { + "system_id": make_name_without_spaces("system-id"), + "hostname": make_name_without_spaces("hostname"), + } + + origin = make_origin() + origin.Devices._handler.read.return_value = [data] + + devices_observed = origin.Devices.read() + devices_expected = origin.Devices([origin.Device(data)]) + self.assertThat(devices_observed, Equals(devices_expected)) From 1af309896d855009dbaac0ae5cb8634ff649b445 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 17:04:38 +0100 Subject: [PATCH 009/245] Rename test_$package.py files to simply test.py, and move AsyncMock up. --- .../bones/tests/{test_bones.py => test.py} | 0 .../flesh/tests/{test_flesh.py => test.py} | 0 maas/client/testing.py | 26 +++++++++++++++++ maas/client/tests/{test_client.py => test.py} | 0 .../utils/tests/{test_utils.py => test.py} | 2 +- maas/client/viscera/testing.py | 29 +------------------ .../tests/{test_viscera.py => test.py} | 0 .../viscera/tests/test_boot_resources.py | 6 ++-- 8 files changed, 30 insertions(+), 33 deletions(-) rename maas/client/bones/tests/{test_bones.py => test.py} (100%) rename maas/client/flesh/tests/{test_flesh.py => test.py} (100%) rename maas/client/tests/{test_client.py => test.py} (100%) rename maas/client/utils/tests/{test_utils.py => test.py} (99%) rename maas/client/viscera/tests/{test_viscera.py => test.py} (100%) diff --git a/maas/client/bones/tests/test_bones.py b/maas/client/bones/tests/test.py similarity index 100% rename from maas/client/bones/tests/test_bones.py rename to maas/client/bones/tests/test.py diff --git a/maas/client/flesh/tests/test_flesh.py b/maas/client/flesh/tests/test.py similarity index 100% rename from maas/client/flesh/tests/test_flesh.py rename to maas/client/flesh/tests/test.py diff --git a/maas/client/testing.py b/maas/client/testing.py index de69502..ed25223 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -1,6 +1,7 @@ """Testing framework for `maas.client`.""" __all__ = [ + "AsyncMock", "make_file", "make_mac_address", "make_name", @@ -182,3 +183,28 @@ def patch(self, obj, attribute, value=mock.sentinel.unset): value = mock.MagicMock(__name__=attribute) super(TestCase, self).patch(obj, attribute, value) return value + + +class AsyncMock(mock.Mock): + """Mock that is "future-like"; see PEP-492 for the details. + + The new `await` syntax chokes on arguments that are not future-like, i.e. + have an `__await__` call, so we have to fool it. + """ + + def __call__(_mock_self, *args, **kwargs): + callup = super(AsyncMock, _mock_self).__call__ + call = partial(callup, *args, **kwargs) + return Awaitable(call) + + +class Awaitable: + """Wrap a "normal" call in a future-like object.""" + + def __init__(self, call): + super(Awaitable, self).__init__() + self._call = call + + def __await__(self): + yield # This serves only to make this a generator. + return self._call() diff --git a/maas/client/tests/test_client.py b/maas/client/tests/test.py similarity index 100% rename from maas/client/tests/test_client.py rename to maas/client/tests/test.py diff --git a/maas/client/utils/tests/test_utils.py b/maas/client/utils/tests/test.py similarity index 99% rename from maas/client/utils/tests/test_utils.py rename to maas/client/utils/tests/test.py index b9f2215..f2ff13d 100644 --- a/maas/client/utils/tests/test_utils.py +++ b/maas/client/utils/tests/test.py @@ -24,12 +24,12 @@ utils, ) from ...testing import ( + AsyncMock, make_name, make_name_without_spaces, make_string, TestCase, ) -from ...viscera.testing import AsyncMock from ..creds import Credentials diff --git a/maas/client/viscera/testing.py b/maas/client/viscera/testing.py index 216c623..c1ffd21 100644 --- a/maas/client/viscera/testing.py +++ b/maas/client/viscera/testing.py @@ -1,17 +1,15 @@ """ Testing framework for maas.client.viscera """ __all__ = [ - 'AsyncMock', - 'Awaitable', 'bind', ] -from functools import partial from itertools import chain from typing import Mapping from unittest.mock import Mock from . import OriginBase +from ..testing import AsyncMock def bind(*objects, session=None): @@ -49,28 +47,3 @@ def _flatten_to_items(thing): } return OriginBase(session, objects=objects) - - -class AsyncMock(Mock): - """Mock that is "future-like"; see PEP-492 for the details. - - The new `await` syntax chokes on arguments that are not future-like, i.e. - have an `__await__` call, so we have to fool it. - """ - - def __call__(_mock_self, *args, **kwargs): - callup = super(AsyncMock, _mock_self).__call__ - call = partial(callup, *args, **kwargs) - return Awaitable(call) - - -class Awaitable: - """Wrap a "normal" call in a future-like object.""" - - def __init__(self, call): - super(Awaitable, self).__init__() - self._call = call - - def __await__(self): - yield # This serves only to make this a generator. - return self._call() diff --git a/maas/client/viscera/tests/test_viscera.py b/maas/client/viscera/tests/test.py similarity index 100% rename from maas/client/viscera/tests/test_viscera.py rename to maas/client/viscera/tests/test.py diff --git a/maas/client/viscera/tests/test_boot_resources.py b/maas/client/viscera/tests/test_boot_resources.py index 5826582..3499164 100644 --- a/maas/client/viscera/tests/test_boot_resources.py +++ b/maas/client/viscera/tests/test_boot_resources.py @@ -21,15 +21,13 @@ from .. import boot_resources from ...testing import ( + AsyncMock, make_name_without_spaces, make_string, pick_bool, TestCase, ) -from ..testing import ( - AsyncMock, - bind, -) +from ..testing import bind def make_origin(): From 07652383ef859ae5c7c522e0cbd89202eaf7899e Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 20 Feb 2017 18:31:09 +0100 Subject: [PATCH 010/245] Move fetch_api_description to m.client.bones.helpers. --- maas/client/bones/__init__.py | 30 ++--- maas/client/bones/helpers.py | 41 ++++++ maas/client/bones/testing/__init__.py | 102 +++++++++++++++ .../bones/{tests => testing}/api20.json | 0 maas/client/bones/tests/test.py | 117 +++--------------- maas/client/bones/tests/test_helpers.py | 65 ++++++++++ maas/client/utils/__init__.py | 20 +-- maas/client/utils/connect.py | 15 ++- maas/client/utils/login.py | 15 ++- maas/client/utils/tests/test.py | 31 +---- maas/client/utils/tests/test_connect.py | 14 ++- maas/client/utils/tests/test_login.py | 16 ++- 12 files changed, 273 insertions(+), 193 deletions(-) create mode 100644 maas/client/bones/helpers.py create mode 100644 maas/client/bones/testing/__init__.py rename maas/client/bones/{tests => testing}/api20.json (100%) create mode 100644 maas/client/bones/tests/test_helpers.py diff --git a/maas/client/bones/__init__.py b/maas/client/bones/__init__.py index defc5b6..b9459a1 100644 --- a/maas/client/bones/__init__.py +++ b/maas/client/bones/__init__.py @@ -13,14 +13,13 @@ Iterable, namedtuple, ) -from http import HTTPStatus import json import re -from urllib.parse import urljoin import aiohttp import aiohttp.errors +from . import helpers from .. import utils from ..utils import profiles from ..utils.connect import connect @@ -38,23 +37,16 @@ class SessionAPI: 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, credentials=credentials, insecure=insecure) + except helpers.RemoteError as error: + # For now just re-raise as SessionError. + raise SessionError(str(error)) + else: + session = cls(description, credentials) + session.insecure = insecure + return session @classmethod def fromProfile(cls, profile): diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py new file mode 100644 index 0000000..4ab224b --- /dev/null +++ b/maas/client/bones/helpers.py @@ -0,0 +1,41 @@ +"""Miscellaneous helpers for Bones.""" + +__all__ = [ + "fetch_api_description", + "RemoteError", +] + +from http import HTTPStatus +from typing import Optional +from urllib.parse import urljoin + +import aiohttp +import aiohttp.errors + +from ..utils.creds import Credentials +from ..utils.typecheck import typed + + +class RemoteError(Exception): + """Miscellaneous error related to a remote system.""" + + +@typed +async def fetch_api_description( + url: str, credentials: Optional[Credentials]=None, + insecure: bool=False): + """Fetch the API description from the remote 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 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() diff --git a/maas/client/bones/testing/__init__.py b/maas/client/bones/testing/__init__.py new file mode 100644 index 0000000..e8c2517 --- /dev/null +++ b/maas/client/bones/testing/__init__.py @@ -0,0 +1,102 @@ +"""Testing helpers for the Bones API.""" + +__all__ = [ + "api_descriptions", + "DescriptionServer", + "list_api_descriptions", +] + +from fnmatch import fnmatchcase +import http +import http.server +import json +from os.path import splitext +from pathlib import Path +import re +import threading + +import fixtures +from pkg_resources import ( + resource_filename, + resource_listdir, +) + + +def list_api_descriptions(): + for filename in resource_listdir(__name__, "."): + if fnmatchcase(filename, "api*.json"): + path = resource_filename(__name__, filename) + name, _ = splitext(filename) + yield name, Path(path) + + +def load_api_descriptions(): + for name, path in list_api_descriptions(): + description = path.read_text("utf-8") + yield name, json.loads(description) + + +api_descriptions = list(load_api_descriptions()) +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/tests/api20.json b/maas/client/bones/testing/api20.json similarity index 100% rename from maas/client/bones/tests/api20.json rename to maas/client/bones/testing/api20.json diff --git a/maas/client/bones/tests/test.py b/maas/client/bones/tests/test.py index 28708d9..23ffc78 100644 --- a/maas/client/bones/tests/test.py +++ b/maas/client/bones/tests/test.py @@ -2,18 +2,11 @@ __all__ = [] -from fnmatch import fnmatchcase -import http -import http.server import json -from os.path import splitext -from pathlib import Path -import re -import threading +import random from unittest.mock import ( ANY, Mock, - sentinel, ) from urllib.parse import ( parse_qsl, @@ -21,95 +14,22 @@ ) from uuid import uuid1 -import fixtures -from pkg_resources import ( - resource_filename, - resource_listdir, -) from testtools.matchers import ( Equals, + Is, MatchesStructure, ) +from .. import testing from ... import bones from ...testing import TestCase from ...utils.tests.test_auth import make_credentials -def list_api_descriptions(): - for filename in resource_listdir(__name__, "."): - if fnmatchcase(filename, "api*.json"): - path = resource_filename(__name__, filename) - name, _ = splitext(filename) - yield name, Path(path) - - -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) - - class TestSessionAPI(TestCase): def test__fromURL_raises_SessionError_when_request_fails(self): - fixture = self.useFixture(DescriptionServer(b"bogus")) + fixture = self.useFixture(testing.DescriptionServer(b"bogus")) error = self.assertRaises( bones.SessionError, self.loop.run_until_complete, bones.SessionAPI.fromURL(fixture.url + "bogus/")) @@ -118,7 +38,7 @@ def test__fromURL_raises_SessionError_when_request_fails(self): str(error)) def test__fromURL_raises_SessionError_when_content_not_json(self): - fixture = self.useFixture(DescriptionServer()) + fixture = self.useFixture(testing.DescriptionServer()) fixture.handler.content_type = "text/json" error = self.assertRaises( bones.SessionError, self.loop.run_until_complete, @@ -128,17 +48,18 @@ def test__fromURL_raises_SessionError_when_content_not_json(self): str(error)) def test__fromURL_sets_credentials_on_session(self): - fixture = self.useFixture(DescriptionServer()) + fixture = self.useFixture(testing.DescriptionServer()) credentials = make_credentials() session = self.loop.run_until_complete( bones.SessionAPI.fromURL(fixture.url, credentials=credentials)) self.assertIs(credentials, session.credentials) def test__fromURL_sets_insecure_on_session(self): - fixture = self.useFixture(DescriptionServer()) + insecure = random.choice((True, False)) + fixture = self.useFixture(testing.DescriptionServer()) session = self.loop.run_until_complete( - bones.SessionAPI.fromURL(fixture.url, insecure=sentinel.insecure)) - self.assertIs(sentinel.insecure, session.insecure) + bones.SessionAPI.fromURL(fixture.url, insecure=insecure)) + self.assertThat(session.insecure, Is(insecure)) class TestSessionAPI_APIVersions(TestCase): @@ -146,12 +67,12 @@ class TestSessionAPI_APIVersions(TestCase): scenarios = tuple( (name, dict(path=path)) - for name, path in list_api_descriptions() + for name, path in testing.list_api_descriptions() ) def test__fromURL_downloads_description(self): description = self.path.read_bytes() - fixture = self.useFixture(DescriptionServer(description)) + fixture = self.useFixture(testing.DescriptionServer(description)) session = self.loop.run_until_complete( bones.SessionAPI.fromURL(fixture.url)) self.assertEqual( @@ -159,22 +80,12 @@ def test__fromURL_downloads_description(self): session.description) -def load_api_descriptions(): - for name, path in list_api_descriptions(): - description = path.read_text("utf-8") - yield name, json.loads(description) - - -api_descriptions = list(load_api_descriptions()) -assert len(api_descriptions) != 0 - - class TestActionAPI_APIVersions(TestCase): """Tests for `ActionAPI` with multiple API versions.""" scenarios = tuple( (name, dict(description=description)) - for name, description in api_descriptions + for name, description in testing.api_descriptions ) def test__Version_read(self): @@ -200,7 +111,7 @@ class TestCallAPI_APIVersions(TestCase): scenarios = tuple( (name, dict(description=description)) - for name, description in api_descriptions + for name, description in testing.api_descriptions ) def test__marshals_lists_into_query_as_repeat_parameters(self): diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py new file mode 100644 index 0000000..398d120 --- /dev/null +++ b/maas/client/bones/tests/test_helpers.py @@ -0,0 +1,65 @@ +"""Tests for `maas.client.utils.remote`.""" + +import json + +from testtools.matchers import Equals + +from .. import testing +from ...testing import ( + make_name, + TestCase, +) +from ...utils.auth import Credentials +from ..helpers import ( + fetch_api_description, + RemoteError, +) + + +def make_credentials(): + return Credentials( + make_name('consumer_key'), + make_name('token_key'), + make_name('secret_key'), + ) + + +class TestFetchAPIDescription(TestCase): + """Tests for `fetch_api_description`.""" + + def test__raises_RemoteError_when_request_fails(self): + fixture = self.useFixture(testing.DescriptionServer(b"bogus")) + error = self.assertRaises( + RemoteError, self.loop.run_until_complete, + fetch_api_description(fixture.url + "bogus/")) + self.assertEqual( + fixture.url + "bogus/ -> 404 Not Found", + str(error)) + + def test__raises_RemoteError_when_content_not_json(self): + fixture = self.useFixture(testing.DescriptionServer()) + fixture.handler.content_type = "text/json" + error = self.assertRaises( + RemoteError, self.loop.run_until_complete, + fetch_api_description(fixture.url)) + self.assertEqual( + "Expected application/json, got: text/json", + str(error)) + + +class TestFetchAPIDescription_APIVersions(TestCase): + """Tests for `fetch_api_description` with multiple API versions.""" + + scenarios = tuple( + (name, dict(path=path)) + for name, path in testing.list_api_descriptions() + ) + + def test__downloads_description(self): + description = self.path.read_bytes() + fixture = self.useFixture(testing.DescriptionServer(description)) + description_fetched = self.loop.run_until_complete( + fetch_api_description(fixture.url)) + self.assertThat( + description_fetched, Equals( + json.loads(description.decode("utf-8")))) diff --git a/maas/client/utils/__init__.py b/maas/client/utils/__init__.py index 9b9ac4e..59bf37d 100644 --- a/maas/client/utils/__init__.py +++ b/maas/client/utils/__init__.py @@ -1,4 +1,4 @@ -"""Utilities for the Alburnum MAAS client.""" +"""Utilities for the MAAS client.""" __all__ = [ "api_url", @@ -29,22 +29,17 @@ import sys import threading from time import time -from typing import Optional from urllib.parse import ( - ParseResult, quote_plus, urlparse, ) from oauthlib import oauth1 -from .async import asynchronous -from .creds import Credentials from .multipart import ( build_multipart_message, encode_multipart_message, ) -from .typecheck import typed def urlencode(data): @@ -334,16 +329,3 @@ def __exit__(self, *exc_info): if self.stream.isatty(): self.__done.set() self.__thread.join() - - -@typed -@asynchronous -async def fetch_api_description( - url: ParseResult, credentials: Optional[Credentials], - insecure: bool): - """Fetch the API description from the remote MAAS instance.""" - # Circular import. - from .. import bones - session = await bones.SessionAPI.fromURL( - url.geturl(), credentials=credentials, insecure=insecure) - return session.description diff --git a/maas/client/utils/connect.py b/maas/client/utils/connect.py index 4012958..58c3602 100644 --- a/maas/client/utils/connect.py +++ b/maas/client/utils/connect.py @@ -7,19 +7,18 @@ from urllib.parse import urlparse -from . import ( - api_url, - fetch_api_description, -) +from . import api_url from .creds import Credentials from .profiles import Profile +from .async import asynchronous class ConnectError(Exception): """An error with connecting.""" -def connect(url, *, apikey=None, insecure=False): +@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 @@ -51,7 +50,11 @@ def connect(url, *, apikey=None, insecure=False): else: credentials = Credentials.parse(apikey) + # Circular import. + from ..bones.helpers import fetch_api_description + description = await fetch_api_description(url, credentials, insecure) + # Return a new (unsaved) profile. return Profile( name=url.netloc, url=url.geturl(), credentials=credentials, - description=fetch_api_description(url, credentials, insecure)) + description=description) diff --git a/maas/client/utils/login.py b/maas/client/utils/login.py index 5313769..e1c244d 100644 --- a/maas/client/utils/login.py +++ b/maas/client/utils/login.py @@ -14,10 +14,8 @@ from urllib.parse import urlparse -from . import ( - api_url, - fetch_api_description, -) +from . import api_url +from .async import asynchronous from .auth import obtain_token from .profiles import Profile @@ -34,7 +32,8 @@ class UsernameWithoutPassword(LoginError): """A user-name was provided without a corresponding password.""" -def login(url, *, username=None, password=None, insecure=False): +@asynchronous +async def login(url, *, 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 @@ -90,7 +89,11 @@ def login(url, *, username=None, password=None, insecure=False): credentials = obtain_token( url.geturl(), username, password, insecure=insecure) + # Circular import. + from ..bones.helpers import fetch_api_description + description = await fetch_api_description(url, credentials, insecure) + # Return a new (unsaved) profile. return Profile( name=url.netloc, url=url.geturl(), credentials=credentials, - description=fetch_api_description(url, credentials, insecure)) + description=description) diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index f2ff13d..cec095d 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -7,30 +7,21 @@ from itertools import cycle import os import os.path -import random from unittest.mock import sentinel -from urllib.parse import urlparse from testtools.matchers import ( AfterPreprocessing, Equals, - Is, MatchesListwise, ) from twisted.internet.task import Clock -from ... import ( - bones, - utils, -) +from ... import utils from ...testing import ( - AsyncMock, - make_name, make_name_without_spaces, make_string, TestCase, ) -from ..creds import Credentials class TestMAASOAuth(TestCase): @@ -439,23 +430,3 @@ def test_intervals_can_be_an_iterable(self): self.assertRetry(clock, next(gen_retries), 103.5, -98.5, 0.0) # All done. self.assertRaises(StopIteration, next, gen_retries) - - -class TestFetchAPIDescription(TestCase): - """Tests for `fetch_api_description`.""" - - def test__calls_through_to_SessionAPI(self): - fromURL = self.patch(bones.SessionAPI, "fromURL", AsyncMock()) - fromURL.return_value.description = sentinel.description - - url = urlparse("http://maas.example.com:5420/MAAS/") - credentials = Credentials( - make_name('consumer_key'), make_name('token_key'), - make_name('secret_key')) - insecure = random.choice((True, False)) - - self.assertThat( - utils.fetch_api_description(url, credentials, insecure), - Is(sentinel.description)) - fromURL.assert_called_once_with( - url.geturl(), credentials=credentials, insecure=insecure) diff --git a/maas/client/utils/tests/test_connect.py b/maas/client/utils/tests/test_connect.py index 1130935..d8e1fc7 100644 --- a/maas/client/utils/tests/test_connect.py +++ b/maas/client/utils/tests/test_connect.py @@ -15,7 +15,9 @@ connect, profiles, ) +from ...bones import helpers from ...testing import ( + AsyncMock, make_name_without_spaces, TestCase, ) @@ -27,12 +29,14 @@ class TestConnect(TestCase): def setUp(self): super(TestConnect, self).setUp() - self.patch(connect, "fetch_api_description").return_value = {} + self.patch( + helpers, "fetch_api_description", + AsyncMock(return_value={})) def test__anonymous_when_no_apikey_provided(self): # Connect without an apikey. profile = connect.connect("http://example.org:5240/MAAS/") - connect.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), None, False) # A Profile instance was returned with no credentials. @@ -45,7 +49,7 @@ def test__connected_when_apikey_provided(self): profile = connect.connect( "http://example.org:5240/MAAS/", apikey=str(credentials)) # The description was fetched. - connect.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), credentials, False) # A Profile instance was returned with the expected credentials. @@ -73,13 +77,13 @@ def test__profile_is_given_default_name_based_on_URL(self): self.assertThat(profile.name, Equals(domain)) def test__API_description_is_saved_in_profile(self): - description = connect.fetch_api_description.return_value = { + description = helpers.fetch_api_description.return_value = { "foo": "bar"} profile = connect.connect("http://example.org:5240/MAAS/") self.assertThat(profile.description, Equals(description)) def test__API_description_is_fetched_insecurely_if_requested(self): connect.connect("http://example.org:5240/MAAS/", insecure=True) - connect.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), None, True) diff --git a/maas/client/utils/tests/test_login.py b/maas/client/utils/tests/test_login.py index e99a985..4fe0d4e 100644 --- a/maas/client/utils/tests/test_login.py +++ b/maas/client/utils/tests/test_login.py @@ -15,7 +15,10 @@ login, profiles, ) +from ...bones import helpers from ...testing import ( + AsyncMock, + make_name, make_name_without_spaces, TestCase, ) @@ -28,14 +31,16 @@ class TestLogin(TestCase): def setUp(self): super(TestLogin, self).setUp() self.patch(login, "obtain_token").return_value = None - self.patch(login, "fetch_api_description").return_value = {} + self.patch( + helpers, "fetch_api_description", + AsyncMock(return_value={})) def test__anonymous_when_neither_username_nor_password_provided(self): # Log-in without a user-name or a password. profile = login.login("http://example.org:5240/MAAS/") # No token was obtained, but the description was fetched. login.obtain_token.assert_not_called() - login.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), None, False) # A Profile instance was returned with no credentials. @@ -50,7 +55,7 @@ def test__authenticated_when_username_and_password_provided(self): login.obtain_token.assert_called_once_with( "http://example.org:5240/MAAS/api/2.0/", "foo", "bar", insecure=False) - login.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), credentials, False) # A Profile instance was returned with the expected credentials. @@ -98,7 +103,8 @@ def test__profile_is_given_default_name_based_on_URL(self): self.assertThat(profile.name, Equals(domain)) def test__API_description_is_saved_in_profile(self): - description = login.fetch_api_description.return_value = {"foo": "bar"} + description = {make_name("key"): make_name("value")} + helpers.fetch_api_description.return_value = description profile = login.login("http://example.org:5240/MAAS/") self.assertThat(profile.description, Equals(description)) @@ -110,7 +116,7 @@ def test__API_token_is_fetched_insecurely_if_requested(self): def test__API_description_is_fetched_insecurely_if_requested(self): login.login("http://example.org:5240/MAAS/", insecure=True) - login.fetch_api_description.assert_called_once_with( + helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), None, True) From a838c26ce0238e87f7a183f732292ba290942bef Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 21 Feb 2017 09:54:54 +0100 Subject: [PATCH 011/245] Move connect and login into m.c.bones.helpers. --- maas/client/bones/__init__.py | 6 +- maas/client/bones/helpers.py | 141 ++++++++++++++- maas/client/bones/tests/test_helpers.py | 217 +++++++++++++++++++++--- maas/client/flesh/profiles.py | 6 +- maas/client/utils/connect.py | 60 ------- maas/client/utils/login.py | 99 ----------- maas/client/utils/tests/test_connect.py | 89 ---------- maas/client/utils/tests/test_login.py | 136 --------------- 8 files changed, 343 insertions(+), 411 deletions(-) delete mode 100644 maas/client/utils/connect.py delete mode 100644 maas/client/utils/login.py delete mode 100644 maas/client/utils/tests/test_connect.py delete mode 100644 maas/client/utils/tests/test_login.py diff --git a/maas/client/bones/__init__.py b/maas/client/bones/__init__.py index b9459a1..81a79a8 100644 --- a/maas/client/bones/__init__.py +++ b/maas/client/bones/__init__.py @@ -22,8 +22,6 @@ from . import helpers from .. import utils from ..utils import profiles -from ..utils.connect import connect -from ..utils.login import login class SessionError(Exception): @@ -74,7 +72,7 @@ def login( an unsaved `Profile` instance, and the latter is a `SessionAPI` instance made using the profile. """ - profile = login( + profile = helpers.login( url=url, username=username, password=password, insecure=insecure) session = cls(profile.description, profile.credentials) session.insecure = insecure @@ -89,7 +87,7 @@ def connect( an unsaved `Profile` instance, and the latter is a `SessionAPI` instance made using the profile. """ - profile = connect( + profile = helpers.connect( url=url, apikey=apikey, insecure=insecure) session = cls(profile.description, profile.credentials) session.insecure = insecure diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index 4ab224b..75dc1bb 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -1,18 +1,31 @@ """Miscellaneous helpers for Bones.""" __all__ = [ + "connect", + "ConnectError", "fetch_api_description", + "login", + "LoginError", + "PasswordWithoutUsername", "RemoteError", + "UsernameWithoutPassword", ] from http import HTTPStatus from typing import Optional -from urllib.parse import urljoin +from urllib.parse import ( + urljoin, + urlparse, +) import aiohttp import aiohttp.errors +from ..utils import api_url +from ..utils.async import asynchronous +from ..utils.auth import obtain_token from ..utils.creds import Credentials +from ..utils.profiles import Profile from ..utils.typecheck import typed @@ -39,3 +52,129 @@ async def fetch_api_description( % response.content_type) else: return await response.json() + + +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) + + # Circular import. + from ..bones.helpers import fetch_api_description + description = await fetch_api_description(url, credentials, insecure) + + # Return a new (unsaved) profile. + return Profile( + name=url.netloc, url=url.geturl(), credentials=credentials, + description=description) + + +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.""" + + +@asynchronous +async def login(url, *, 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 + + """ + 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 is None or len(password) == 0: + credentials = None # Anonymous. + else: + raise PasswordWithoutUsername( + "Password provided without user-name; specify user-name.") + else: + if password is None: + raise UsernameWithoutPassword( + "User-name provided without password; specify password.") + else: + credentials = obtain_token( + url.geturl(), username, password, insecure=insecure) + + # Circular import. + from ..bones.helpers import fetch_api_description + description = await fetch_api_description(url, credentials, insecure) + + # Return a new (unsaved) profile. + return Profile( + name=url.netloc, url=url.geturl(), credentials=credentials, + description=description) diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index 398d120..1d69a81 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -1,27 +1,29 @@ """Tests for `maas.client.utils.remote`.""" import json +from urllib.parse import urlparse -from testtools.matchers import Equals +from testtools.matchers import ( + Equals, + Is, + IsInstance, +) -from .. import testing +from .. import ( + helpers, + testing, +) from ...testing import ( + AsyncMock, make_name, + make_name_without_spaces, TestCase, ) -from ...utils.auth import Credentials -from ..helpers import ( - fetch_api_description, - RemoteError, +from ...utils import ( + api_url, + profiles, ) - - -def make_credentials(): - return Credentials( - make_name('consumer_key'), - make_name('token_key'), - make_name('secret_key'), - ) +from ...utils.tests.test_auth import make_credentials class TestFetchAPIDescription(TestCase): @@ -30,8 +32,8 @@ class TestFetchAPIDescription(TestCase): def test__raises_RemoteError_when_request_fails(self): fixture = self.useFixture(testing.DescriptionServer(b"bogus")) error = self.assertRaises( - RemoteError, self.loop.run_until_complete, - fetch_api_description(fixture.url + "bogus/")) + helpers.RemoteError, self.loop.run_until_complete, + helpers.fetch_api_description(fixture.url + "bogus/")) self.assertEqual( fixture.url + "bogus/ -> 404 Not Found", str(error)) @@ -40,8 +42,8 @@ def test__raises_RemoteError_when_content_not_json(self): fixture = self.useFixture(testing.DescriptionServer()) fixture.handler.content_type = "text/json" error = self.assertRaises( - RemoteError, self.loop.run_until_complete, - fetch_api_description(fixture.url)) + helpers.RemoteError, self.loop.run_until_complete, + helpers.fetch_api_description(fixture.url)) self.assertEqual( "Expected application/json, got: text/json", str(error)) @@ -59,7 +61,184 @@ def test__downloads_description(self): description = self.path.read_bytes() fixture = self.useFixture(testing.DescriptionServer(description)) description_fetched = self.loop.run_until_complete( - fetch_api_description(fixture.url)) + helpers.fetch_api_description(fixture.url)) self.assertThat( description_fetched, Equals( json.loads(description.decode("utf-8")))) + + +class TestConnect(TestCase): + """Tests for `maas.client.utils.connect.connect`.""" + + def setUp(self): + super(TestConnect, self).setUp() + self.patch( + helpers, "fetch_api_description", + AsyncMock(return_value={})) + + def test__anonymous_when_no_apikey_provided(self): + # Connect without an apikey. + profile = helpers.connect("http://example.org:5240/MAAS/") + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + None, False) + # A Profile instance was returned with no credentials. + self.assertThat(profile, IsInstance(profiles.Profile)) + self.assertThat(profile.credentials, Is(None)) + + def test__connected_when_apikey_provided(self): + credentials = make_credentials() + # Connect with an apikey. + profile = helpers.connect( + "http://example.org:5240/MAAS/", apikey=str(credentials)) + # The description was fetched. + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + credentials, False) + # A Profile instance was returned with the expected credentials. + self.assertThat(profile, IsInstance(profiles.Profile)) + self.assertThat(profile.credentials, Equals(credentials)) + + def test__complains_when_username_in_URL(self): + self.assertRaises( + helpers.ConnectError, helpers.connect, + "http://foo:bar@example.org:5240/MAAS/") + + def test__complains_when_password_in_URL(self): + self.assertRaises( + helpers.ConnectError, helpers.connect, + "http://:bar@example.org:5240/MAAS/") + + def test__URL_is_normalised_to_point_at_API_endpoint(self): + profile = helpers.connect("http://example.org:5240/MAAS/") + self.assertThat(profile.url, Equals( + api_url("http://example.org:5240/MAAS/"))) + + def test__profile_is_given_default_name_based_on_URL(self): + domain = make_name_without_spaces("domain") + profile = helpers.connect("http://%s/MAAS/" % domain) + self.assertThat(profile.name, Equals(domain)) + + def test__API_description_is_saved_in_profile(self): + description = helpers.fetch_api_description.return_value = { + "foo": "bar"} + profile = helpers.connect("http://example.org:5240/MAAS/") + self.assertThat(profile.description, Equals(description)) + + def test__API_description_is_fetched_insecurely_if_requested(self): + helpers.connect("http://example.org:5240/MAAS/", insecure=True) + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + None, True) + + +class TestLogin(TestCase): + """Tests for `maas.client.utils.login.login`.""" + + def setUp(self): + super(TestLogin, self).setUp() + self.patch(helpers, "obtain_token").return_value = None + self.patch( + helpers, "fetch_api_description", + AsyncMock(return_value={})) + + def test__anonymous_when_neither_username_nor_password_provided(self): + # Log-in without a user-name or a password. + profile = helpers.login("http://example.org:5240/MAAS/") + # No token was obtained, but the description was fetched. + helpers.obtain_token.assert_not_called() + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + None, False) + # A Profile instance was returned with no credentials. + self.assertThat(profile, IsInstance(profiles.Profile)) + self.assertThat(profile.credentials, Is(None)) + + def test__authenticated_when_username_and_password_provided(self): + credentials = make_credentials() + helpers.obtain_token.return_value = credentials + # Log-in with a user-name and a password. + profile = helpers.login("http://foo:bar@example.org:5240/MAAS/") + # A token was obtained, and the description was fetched. + helpers.obtain_token.assert_called_once_with( + "http://example.org:5240/MAAS/api/2.0/", + "foo", "bar", insecure=False) + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + credentials, False) + # A Profile instance was returned with the expected credentials. + self.assertThat(profile, IsInstance(profiles.Profile)) + self.assertThat(profile.credentials, Is(credentials)) + + def test__complains_when_username_but_not_password(self): + self.assertRaises( + helpers.UsernameWithoutPassword, helpers.login, + "http://example.org:5240/MAAS/", username="alice") + + def test__complains_when_password_but_not_username(self): + self.assertRaises( + helpers.PasswordWithoutUsername, helpers.login, + "http://example.org:5240/MAAS/", password="wonderland") + + def test__complains_when_username_in_URL_and_passed_explicitly(self): + self.assertRaises( + helpers.LoginError, helpers.login, + "http://foo:bar@example.org:5240/MAAS/", username="alice") + + def test__complains_when_empty_username_in_URL_and_passed_explicitly(self): + self.assertRaises( + helpers.LoginError, helpers.login, + "http://:bar@example.org:5240/MAAS/", username="alice") + + def test__complains_when_password_in_URL_and_passed_explicitly(self): + self.assertRaises( + helpers.LoginError, helpers.login, + "http://foo:bar@example.org:5240/MAAS/", password="wonderland") + + def test__complains_when_empty_password_in_URL_and_passed_explicitly(self): + self.assertRaises( + helpers.LoginError, helpers.login, + "http://foo:@example.org:5240/MAAS/", password="wonderland") + + def test__URL_is_normalised_to_point_at_API_endpoint(self): + profile = helpers.login("http://example.org:5240/MAAS/") + self.assertThat(profile.url, Equals( + api_url("http://example.org:5240/MAAS/"))) + + def test__profile_is_given_default_name_based_on_URL(self): + domain = make_name_without_spaces("domain") + profile = helpers.login("http://%s/MAAS/" % domain) + self.assertThat(profile.name, Equals(domain)) + + def test__API_description_is_saved_in_profile(self): + description = {make_name("key"): make_name("value")} + helpers.fetch_api_description.return_value = description + profile = helpers.login("http://example.org:5240/MAAS/") + self.assertThat(profile.description, Equals(description)) + + def test__API_token_is_fetched_insecurely_if_requested(self): + helpers.login("http://foo:bar@example.org:5240/MAAS/", insecure=True) + helpers.obtain_token.assert_called_once_with( + "http://example.org:5240/MAAS/api/2.0/", + "foo", "bar", insecure=True) + + def test__API_description_is_fetched_insecurely_if_requested(self): + helpers.login("http://example.org:5240/MAAS/", insecure=True) + helpers.fetch_api_description.assert_called_once_with( + urlparse("http://example.org:5240/MAAS/api/2.0/"), + None, True) + + def test__uses_username_from_URL_if_set(self): + helpers.login("http://foo@maas.io/", password="bar") + helpers.obtain_token.assert_called_once_with( + "http://maas.io/api/2.0/", "foo", "bar", insecure=False) + + def test__uses_username_and_password_from_URL_if_set(self): + helpers.login("http://foo:bar@maas.io/") + helpers.obtain_token.assert_called_once_with( + "http://maas.io/api/2.0/", "foo", "bar", insecure=False) + + def test__uses_empty_username_and_password_in_URL_if_set(self): + helpers.login("http://:@maas.io/") + helpers.obtain_token.assert_called_once_with( + "http://maas.io/api/2.0/", "", "", insecure=False) diff --git a/maas/client/flesh/profiles.py b/maas/client/flesh/profiles.py index 99b1ec9..9375b5d 100644 --- a/maas/client/flesh/profiles.py +++ b/maas/client/flesh/profiles.py @@ -18,9 +18,9 @@ bones, utils, ) +from ..bones import helpers from ..utils import ( auth, - login, profiles, ) @@ -90,10 +90,10 @@ def __call__(self, options): while True: try: - profile = login.login( + profile = helpers.login( options.url, username=options.username, password=options.password, insecure=options.insecure) - except login.UsernameWithoutPassword: + except helpers.UsernameWithoutPassword: # Try to obtain the password interactively. options.password = auth.try_getpass("Password: ") if options.password is None: diff --git a/maas/client/utils/connect.py b/maas/client/utils/connect.py deleted file mode 100644 index 58c3602..0000000 --- a/maas/client/utils/connect.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Connect to a remote MAAS instance with an apikey.""" - -__all__ = [ - "connect", - "ConnectError", -] - -from urllib.parse import urlparse - -from . import api_url -from .creds import Credentials -from .profiles import Profile -from .async import asynchronous - - -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) - - # Circular import. - from ..bones.helpers import fetch_api_description - description = await fetch_api_description(url, credentials, insecure) - - # Return a new (unsaved) profile. - return Profile( - name=url.netloc, url=url.geturl(), credentials=credentials, - description=description) diff --git a/maas/client/utils/login.py b/maas/client/utils/login.py deleted file mode 100644 index e1c244d..0000000 --- a/maas/client/utils/login.py +++ /dev/null @@ -1,99 +0,0 @@ -"""Logging-in to a remote MAAS instance with a user-name and password. - -Instead of copy-and-pasting API keys, this allows clients to log-in using -their user-name and password, and automatically retrieve an API key. These -credentials can then be saved with the profile manager. -""" - -__all__ = [ - "login", - "LoginError", - "PasswordWithoutUsername", - "UsernameWithoutPassword", -] - -from urllib.parse import urlparse - -from . import api_url -from .async import asynchronous -from .auth import obtain_token -from .profiles import Profile - - -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.""" - - -@asynchronous -async def login(url, *, 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 - - """ - 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 is None or len(password) == 0: - credentials = None # Anonymous. - else: - raise PasswordWithoutUsername( - "Password provided without user-name; specify user-name.") - else: - if password is None: - raise UsernameWithoutPassword( - "User-name provided without password; specify password.") - else: - credentials = obtain_token( - url.geturl(), username, password, insecure=insecure) - - # Circular import. - from ..bones.helpers import fetch_api_description - description = await fetch_api_description(url, credentials, insecure) - - # Return a new (unsaved) profile. - return Profile( - name=url.netloc, url=url.geturl(), credentials=credentials, - description=description) diff --git a/maas/client/utils/tests/test_connect.py b/maas/client/utils/tests/test_connect.py deleted file mode 100644 index d8e1fc7..0000000 --- a/maas/client/utils/tests/test_connect.py +++ /dev/null @@ -1,89 +0,0 @@ -"""Tests for `maas.client.utils.connect`.""" - -__all__ = [] - -from urllib.parse import urlparse - -from testtools.matchers import ( - Equals, - Is, - IsInstance, -) - -from .. import ( - api_url, - connect, - profiles, -) -from ...bones import helpers -from ...testing import ( - AsyncMock, - make_name_without_spaces, - TestCase, -) -from .test_auth import make_credentials - - -class TestConnect(TestCase): - """Tests for `maas.client.utils.connect.connect`.""" - - def setUp(self): - super(TestConnect, self).setUp() - self.patch( - helpers, "fetch_api_description", - AsyncMock(return_value={})) - - def test__anonymous_when_no_apikey_provided(self): - # Connect without an apikey. - profile = connect.connect("http://example.org:5240/MAAS/") - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - None, False) - # A Profile instance was returned with no credentials. - self.assertThat(profile, IsInstance(profiles.Profile)) - self.assertThat(profile.credentials, Is(None)) - - def test__connected_when_apikey_provided(self): - credentials = make_credentials() - # Connect with an apikey. - profile = connect.connect( - "http://example.org:5240/MAAS/", apikey=str(credentials)) - # The description was fetched. - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - credentials, False) - # A Profile instance was returned with the expected credentials. - self.assertThat(profile, IsInstance(profiles.Profile)) - self.assertThat(profile.credentials, Equals(credentials)) - - def test__complains_when_username_in_URL(self): - self.assertRaises( - connect.ConnectError, connect.connect, - "http://foo:bar@example.org:5240/MAAS/") - - def test__complains_when_password_in_URL(self): - self.assertRaises( - connect.ConnectError, connect.connect, - "http://:bar@example.org:5240/MAAS/") - - def test__URL_is_normalised_to_point_at_API_endpoint(self): - profile = connect.connect("http://example.org:5240/MAAS/") - self.assertThat(profile.url, Equals( - api_url("http://example.org:5240/MAAS/"))) - - def test__profile_is_given_default_name_based_on_URL(self): - domain = make_name_without_spaces("domain") - profile = connect.connect("http://%s/MAAS/" % domain) - self.assertThat(profile.name, Equals(domain)) - - def test__API_description_is_saved_in_profile(self): - description = helpers.fetch_api_description.return_value = { - "foo": "bar"} - profile = connect.connect("http://example.org:5240/MAAS/") - self.assertThat(profile.description, Equals(description)) - - def test__API_description_is_fetched_insecurely_if_requested(self): - connect.connect("http://example.org:5240/MAAS/", insecure=True) - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - None, True) diff --git a/maas/client/utils/tests/test_login.py b/maas/client/utils/tests/test_login.py deleted file mode 100644 index 4fe0d4e..0000000 --- a/maas/client/utils/tests/test_login.py +++ /dev/null @@ -1,136 +0,0 @@ -"""Tests for `maas.client.utils.login`.""" - -__all__ = [] - -from urllib.parse import urlparse - -from testtools.matchers import ( - Equals, - Is, - IsInstance, -) - -from .. import ( - api_url, - login, - profiles, -) -from ...bones import helpers -from ...testing import ( - AsyncMock, - make_name, - make_name_without_spaces, - TestCase, -) -from .test_auth import make_credentials - - -class TestLogin(TestCase): - """Tests for `maas.client.utils.login.login`.""" - - def setUp(self): - super(TestLogin, self).setUp() - self.patch(login, "obtain_token").return_value = None - self.patch( - helpers, "fetch_api_description", - AsyncMock(return_value={})) - - def test__anonymous_when_neither_username_nor_password_provided(self): - # Log-in without a user-name or a password. - profile = login.login("http://example.org:5240/MAAS/") - # No token was obtained, but the description was fetched. - login.obtain_token.assert_not_called() - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - None, False) - # A Profile instance was returned with no credentials. - self.assertThat(profile, IsInstance(profiles.Profile)) - self.assertThat(profile.credentials, Is(None)) - - def test__authenticated_when_username_and_password_provided(self): - credentials = login.obtain_token.return_value = make_credentials() - # Log-in with a user-name and a password. - profile = login.login("http://foo:bar@example.org:5240/MAAS/") - # A token was obtained, and the description was fetched. - login.obtain_token.assert_called_once_with( - "http://example.org:5240/MAAS/api/2.0/", - "foo", "bar", insecure=False) - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - credentials, False) - # A Profile instance was returned with the expected credentials. - self.assertThat(profile, IsInstance(profiles.Profile)) - self.assertThat(profile.credentials, Is(credentials)) - - def test__complains_when_username_but_not_password(self): - self.assertRaises( - login.UsernameWithoutPassword, login.login, - "http://example.org:5240/MAAS/", username="alice") - - def test__complains_when_password_but_not_username(self): - self.assertRaises( - login.PasswordWithoutUsername, login.login, - "http://example.org:5240/MAAS/", password="wonderland") - - def test__complains_when_username_in_URL_and_passed_explicitly(self): - self.assertRaises( - login.LoginError, login.login, - "http://foo:bar@example.org:5240/MAAS/", username="alice") - - def test__complains_when_empty_username_in_URL_and_passed_explicitly(self): - self.assertRaises( - login.LoginError, login.login, - "http://:bar@example.org:5240/MAAS/", username="alice") - - def test__complains_when_password_in_URL_and_passed_explicitly(self): - self.assertRaises( - login.LoginError, login.login, - "http://foo:bar@example.org:5240/MAAS/", password="wonderland") - - def test__complains_when_empty_password_in_URL_and_passed_explicitly(self): - self.assertRaises( - login.LoginError, login.login, - "http://foo:@example.org:5240/MAAS/", password="wonderland") - - def test__URL_is_normalised_to_point_at_API_endpoint(self): - profile = login.login("http://example.org:5240/MAAS/") - self.assertThat(profile.url, Equals( - api_url("http://example.org:5240/MAAS/"))) - - def test__profile_is_given_default_name_based_on_URL(self): - domain = make_name_without_spaces("domain") - profile = login.login("http://%s/MAAS/" % domain) - self.assertThat(profile.name, Equals(domain)) - - def test__API_description_is_saved_in_profile(self): - description = {make_name("key"): make_name("value")} - helpers.fetch_api_description.return_value = description - profile = login.login("http://example.org:5240/MAAS/") - self.assertThat(profile.description, Equals(description)) - - def test__API_token_is_fetched_insecurely_if_requested(self): - login.login("http://foo:bar@example.org:5240/MAAS/", insecure=True) - login.obtain_token.assert_called_once_with( - "http://example.org:5240/MAAS/api/2.0/", - "foo", "bar", insecure=True) - - def test__API_description_is_fetched_insecurely_if_requested(self): - login.login("http://example.org:5240/MAAS/", insecure=True) - helpers.fetch_api_description.assert_called_once_with( - urlparse("http://example.org:5240/MAAS/api/2.0/"), - None, True) - - def test__uses_username_from_URL_if_set(self): - login.login("http://foo@maas.io/", password="bar") - login.obtain_token.assert_called_once_with( - "http://maas.io/api/2.0/", "foo", "bar", insecure=False) - - def test__uses_username_and_password_from_URL_if_set(self): - login.login("http://foo:bar@maas.io/") - login.obtain_token.assert_called_once_with( - "http://maas.io/api/2.0/", "foo", "bar", insecure=False) - - def test__uses_empty_username_and_password_in_URL_if_set(self): - login.login("http://:@maas.io/") - login.obtain_token.assert_called_once_with( - "http://maas.io/api/2.0/", "", "", insecure=False) From 53690b38e7085cb7274bf9c27c64d4b3f19f64c8 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 21 Feb 2017 10:10:21 +0100 Subject: [PATCH 012/245] Update comment. --- maas/client/bones/tests/test_helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index 1d69a81..a4f8666 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -1,4 +1,4 @@ -"""Tests for `maas.client.utils.remote`.""" +"""Tests for `maas.client.bones.helpers`.""" import json from urllib.parse import urlparse From ed220256be6e17ff0e3a0cb98a6ab3d5c4cc820c Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Thu, 23 Feb 2017 17:46:29 +0100 Subject: [PATCH 013/245] Update setup.py with new location of testing JSON. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 3954ff0..d7e8479 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ namespace_packages=['maas'], packages=find_packages(), package_data={ - 'maas.client.bones.tests': ['*.json'], + 'maas.client.bones.testing': ['*.json'], }, install_requires={ "aiohttp >= 1.1.4", From 57e5802144913270bb932ab1d67982581379889f Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Fri, 24 Feb 2017 17:59:49 +0100 Subject: [PATCH 014/245] Fix spurious test failure in test_obtain_credentials_from_stdin, and move make_credentials to a shared location. --- maas/client/bones/tests/test_helpers.py | 2 +- maas/client/utils/testing.py | 12 ++++++++++++ maas/client/utils/tests/test_auth.py | 15 ++------------- maas/client/utils/tests/test_profiles.py | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 maas/client/utils/testing.py diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index a4f8666..d5a2453 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -23,7 +23,7 @@ api_url, profiles, ) -from ...utils.tests.test_auth import make_credentials +from ...utils.testing import make_credentials class TestFetchAPIDescription(TestCase): diff --git a/maas/client/utils/testing.py b/maas/client/utils/testing.py new file mode 100644 index 0000000..229a06c --- /dev/null +++ b/maas/client/utils/testing.py @@ -0,0 +1,12 @@ +"""Testing helpers for `maas.client.utils`.""" + +from ..testing import make_name_without_spaces +from .creds import Credentials + + +def make_credentials(): + return Credentials( + make_name_without_spaces('consumer_key'), + make_name_without_spaces('token_key'), + make_name_without_spaces('secret_key'), + ) diff --git a/maas/client/utils/tests/test_auth.py b/maas/client/utils/tests/test_auth.py index b2af996..0aae693 100644 --- a/maas/client/utils/tests/test_auth.py +++ b/maas/client/utils/tests/test_auth.py @@ -9,19 +9,8 @@ ) from .. import auth -from ...testing import ( - make_name, - TestCase, -) -from ..creds import Credentials - - -def make_credentials(): - return Credentials( - make_name('consumer_key'), - make_name('token_key'), - make_name('secret_key'), - ) +from ...testing import TestCase +from ..testing import make_credentials class TestAuth(TestCase): diff --git a/maas/client/utils/tests/test_profiles.py b/maas/client/utils/tests/test_profiles.py index 19bd908..62ede70 100644 --- a/maas/client/utils/tests/test_profiles.py +++ b/maas/client/utils/tests/test_profiles.py @@ -24,7 +24,7 @@ ProfileNotFound, ProfileStore, ) -from .test_auth import make_credentials +from ..testing import make_credentials def make_profile(): From ad665cf5058f21dfa7154d8f7f1503ad488873f8 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Fri, 24 Feb 2017 18:04:47 +0100 Subject: [PATCH 015/245] Rename make_credentials to make_Credentials. --- maas/client/bones/tests/test.py | 4 ++-- maas/client/bones/tests/test_helpers.py | 6 +++--- maas/client/utils/testing.py | 2 +- maas/client/utils/tests/test_auth.py | 6 +++--- maas/client/utils/tests/test_profiles.py | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/maas/client/bones/tests/test.py b/maas/client/bones/tests/test.py index 23ffc78..6001dd5 100644 --- a/maas/client/bones/tests/test.py +++ b/maas/client/bones/tests/test.py @@ -23,7 +23,7 @@ from .. import testing from ... import bones from ...testing import TestCase -from ...utils.tests.test_auth import make_credentials +from ...utils.tests.test_auth import make_Credentials class TestSessionAPI(TestCase): @@ -49,7 +49,7 @@ def test__fromURL_raises_SessionError_when_content_not_json(self): def test__fromURL_sets_credentials_on_session(self): fixture = self.useFixture(testing.DescriptionServer()) - credentials = make_credentials() + credentials = make_Credentials() session = self.loop.run_until_complete( bones.SessionAPI.fromURL(fixture.url, credentials=credentials)) self.assertIs(credentials, session.credentials) diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index d5a2453..6c8ae64 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -23,7 +23,7 @@ api_url, profiles, ) -from ...utils.testing import make_credentials +from ...utils.testing import make_Credentials class TestFetchAPIDescription(TestCase): @@ -87,7 +87,7 @@ def test__anonymous_when_no_apikey_provided(self): self.assertThat(profile.credentials, Is(None)) def test__connected_when_apikey_provided(self): - credentials = make_credentials() + credentials = make_Credentials() # Connect with an apikey. profile = helpers.connect( "http://example.org:5240/MAAS/", apikey=str(credentials)) @@ -155,7 +155,7 @@ def test__anonymous_when_neither_username_nor_password_provided(self): self.assertThat(profile.credentials, Is(None)) def test__authenticated_when_username_and_password_provided(self): - credentials = make_credentials() + credentials = make_Credentials() helpers.obtain_token.return_value = credentials # Log-in with a user-name and a password. profile = helpers.login("http://foo:bar@example.org:5240/MAAS/") diff --git a/maas/client/utils/testing.py b/maas/client/utils/testing.py index 229a06c..d67acdd 100644 --- a/maas/client/utils/testing.py +++ b/maas/client/utils/testing.py @@ -4,7 +4,7 @@ from .creds import Credentials -def make_credentials(): +def make_Credentials(): return Credentials( make_name_without_spaces('consumer_key'), make_name_without_spaces('token_key'), diff --git a/maas/client/utils/tests/test_auth.py b/maas/client/utils/tests/test_auth.py index 0aae693..779ec5f 100644 --- a/maas/client/utils/tests/test_auth.py +++ b/maas/client/utils/tests/test_auth.py @@ -10,7 +10,7 @@ from .. import auth from ...testing import TestCase -from ..testing import make_credentials +from ..testing import make_Credentials class TestAuth(TestCase): @@ -30,7 +30,7 @@ def test_try_getpass_eof(self): def test_obtain_credentials_from_stdin(self): # When "-" is passed to obtain_credentials, it reads credentials from # stdin, trims whitespace, and converts it into a 3-tuple of creds. - credentials = make_credentials() + credentials = make_Credentials() stdin = self.patch(sys, "stdin") stdin.readline.return_value = str(credentials) + "\n" self.assertEqual(credentials, auth.obtain_credentials("-")) @@ -39,7 +39,7 @@ def test_obtain_credentials_from_stdin(self): def test_obtain_credentials_via_getpass(self): # When None is passed to obtain_credentials, it attempts to obtain # credentials via getpass, then converts it into a 3-tuple of creds. - credentials = make_credentials() + credentials = make_Credentials() getpass = self.patch(auth, "getpass") getpass.return_value = str(credentials) self.assertEqual(credentials, auth.obtain_credentials(None)) diff --git a/maas/client/utils/tests/test_profiles.py b/maas/client/utils/tests/test_profiles.py index 62ede70..f8805f3 100644 --- a/maas/client/utils/tests/test_profiles.py +++ b/maas/client/utils/tests/test_profiles.py @@ -24,13 +24,13 @@ ProfileNotFound, ProfileStore, ) -from ..testing import make_credentials +from ..testing import make_Credentials def make_profile(): return Profile( name=make_name_without_spaces("name"), url="http://example.com:5240/", - credentials=make_credentials(), description={"resources": []}, + credentials=make_Credentials(), description={"resources": []}, something=make_name_without_spaces("something")) From 58d862170aab9c56866ab34727dc415b007398ee Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 27 Feb 2017 17:13:56 +0100 Subject: [PATCH 016/245] Always send a request body so that Piston always sets request.data (server-side). --- maas/client/utils/__init__.py | 10 ++++------ maas/client/utils/tests/test.py | 25 ++++++++++++------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/maas/client/utils/__init__.py b/maas/client/utils/__init__.py index 59bf37d..19f3b8e 100644 --- a/maas/client/utils/__init__.py +++ b/maas/client/utils/__init__.py @@ -88,12 +88,10 @@ def slurp(opener): (name, slurp(value) if callable(value) else value) for name, value in data) else: - data = list(data) - if len(data) == 0: - headers, body = [], None - else: - message = build_multipart_message(data) - headers, body = encode_multipart_message(message) + # Even if data is empty, construct a multipart request body. Piston + # (server-side) sets `request.data` to `None` if there's no payload. + message = build_multipart_message(data) + headers, body = encode_multipart_message(message) uri = urlparse(uri)._replace(query=urlencode(query)).geturl() return uri, body, headers diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index cec095d..eff2d71 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -77,8 +77,8 @@ class TestPayloadPreparation(TestCase): ("create", {"method": "POST", "data": [], "expected_uri": uri_base, - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), ("read", {"method": "GET", "data": [], "expected_uri": uri_base, @@ -87,13 +87,13 @@ class TestPayloadPreparation(TestCase): ("update", {"method": "PUT", "data": [], "expected_uri": uri_base, - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), ("delete", {"method": "DELETE", "data": [], "expected_uri": uri_base, - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), # With data, PUT, POST, and DELETE requests have their body and # extra headers prepared by build_multipart_message and # encode_multipart_message. For GET requests, the data is @@ -128,8 +128,8 @@ class TestPayloadPreparation(TestCase): ("create", {"method": "POST", "data": [], "expected_uri": uri_base + "?op=something", - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), ("read", {"method": "GET", "data": [], "expected_uri": uri_base + "?op=something", @@ -138,13 +138,13 @@ class TestPayloadPreparation(TestCase): ("update", {"method": "PUT", "data": [], "expected_uri": uri_base + "?op=something", - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), ("delete", {"method": "DELETE", "data": [], "expected_uri": uri_base + "?op=something", - "expected_body": None, - "expected_headers": []}), + "expected_body": sentinel.body, + "expected_headers": sentinel.headers}), # With data, PUT, POST, and DELETE requests have their body and # extra headers prepared by build_multipart_message and # encode_multipart_message. For GET requests, the data is @@ -204,7 +204,6 @@ def test_prepare_payload(self): # encode_multipart_message, when called, is passed the data # unadulterated. if self.expected_body is sentinel.body: - build_multipart.assert_called_once_with(self.data) encode_multipart.assert_called_once_with(sentinel.message) From 209d15057b9e1456c8baf79988f8677515c88ef7 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 27 Feb 2017 17:31:40 +0100 Subject: [PATCH 017/245] Test the Account object type. --- maas/client/viscera/account.py | 4 +- maas/client/viscera/tests/test_account.py | 77 +++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 maas/client/viscera/tests/test_account.py diff --git a/maas/client/viscera/account.py b/maas/client/viscera/account.py index 2c63a2a..f739803 100644 --- a/maas/client/viscera/account.py +++ b/maas/client/viscera/account.py @@ -18,7 +18,9 @@ class AccountType(ObjectType): @typed async def create_credentials(cls) -> Credentials: data = await cls._handler.create_authorisation_token() - return Credentials(**data) + return Credentials( + consumer_key=data["consumer_key"], token_key=data["token_key"], + token_secret=data["token_secret"]) @typed async def delete_credentials(cls, credentials: Credentials) -> None: diff --git a/maas/client/viscera/tests/test_account.py b/maas/client/viscera/tests/test_account.py new file mode 100644 index 0000000..a6dbf45 --- /dev/null +++ b/maas/client/viscera/tests/test_account.py @@ -0,0 +1,77 @@ +"""Test for `maas.client.viscera.account`.""" + +__all__ = [] + +from testtools.matchers import ( + Equals, + IsInstance, + MatchesAll, +) + +from .. import account +from ...testing import ( + make_name_without_spaces, + TestCase, +) +from ...utils import creds +from ...utils.testing import make_Credentials +from ..testing import bind + + +def make_origin(): + # Create a new origin with Account. + return bind(account.Account) + + +class TestAccount(TestCase): + + def test__create_credentials_returns_Credentials(self): + consumer_key = make_name_without_spaces('consumer_key'), + token_key = make_name_without_spaces('token_key'), + token_secret = make_name_without_spaces('token_secret'), + + origin = make_origin() + create_authorisation_token = ( + origin.Account._handler.create_authorisation_token) + create_authorisation_token.return_value = { + "consumer_key": consumer_key, "token_key": token_key, + "token_secret": token_secret, + } + + credentials = origin.Account.create_credentials() + self.assertThat(credentials, MatchesAll( + IsInstance(creds.Credentials), + Equals((consumer_key, token_key, token_secret)), + )) + + def test__create_credentials_ignores_other_keys_in_response(self): + consumer_key = make_name_without_spaces('consumer_key'), + token_key = make_name_without_spaces('token_key'), + token_secret = make_name_without_spaces('token_secret'), + + origin = make_origin() + create_authorisation_token = ( + origin.Account._handler.create_authorisation_token) + create_authorisation_token.return_value = { + "name": "cookie-monster", "fur-colour": "blue", + "consumer_key": consumer_key, "token_key": token_key, + "token_secret": token_secret, + } + + credentials = origin.Account.create_credentials() + self.assertThat(credentials, MatchesAll( + IsInstance(creds.Credentials), + Equals((consumer_key, token_key, token_secret)), + )) + + def test__delete_credentials_sends_token_key(self): + origin = make_origin() + delete_authorisation_token = ( + origin.Account._handler.delete_authorisation_token) + delete_authorisation_token.return_value = None + credentials = make_Credentials() + + origin.Account.delete_credentials(credentials) + + delete_authorisation_token.assert_called_once_with( + token_key=credentials.token_key) From a0efbfd5ef71edd08f3e32368730afec8130a4aa Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 28 Feb 2017 16:49:09 +0100 Subject: [PATCH 018/245] Refactor AsyncMock and Awaitable into four different mocks: AsyncAwaitableMock, AsyncCallableMock, AsyncContextMock, AsyncIterableMock. This more closely matches the different async-ish object types defined in PEP-492. --- maas/client/bones/tests/test_helpers.py | 6 +- maas/client/testing.py | 65 ++++++++++++++----- maas/client/viscera/boot_resources.py | 22 +++---- maas/client/viscera/testing.py | 4 +- .../viscera/tests/test_boot_resources.py | 27 ++++---- 5 files changed, 81 insertions(+), 43 deletions(-) diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index 6c8ae64..dd28517 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -14,7 +14,7 @@ testing, ) from ...testing import ( - AsyncMock, + AsyncCallableMock, make_name, make_name_without_spaces, TestCase, @@ -74,7 +74,7 @@ def setUp(self): super(TestConnect, self).setUp() self.patch( helpers, "fetch_api_description", - AsyncMock(return_value={})) + AsyncCallableMock(return_value={})) def test__anonymous_when_no_apikey_provided(self): # Connect without an apikey. @@ -140,7 +140,7 @@ def setUp(self): self.patch(helpers, "obtain_token").return_value = None self.patch( helpers, "fetch_api_description", - AsyncMock(return_value={})) + AsyncCallableMock(return_value={})) def test__anonymous_when_neither_username_nor_password_provided(self): # Log-in without a user-name or a password. diff --git a/maas/client/testing.py b/maas/client/testing.py index ed25223..413de3d 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -1,7 +1,10 @@ """Testing framework for `maas.client`.""" __all__ = [ - "AsyncMock", + "AsyncAwaitableMock", + "AsyncCallableMock", + "AsyncContextMock", + "AsyncIterableMock", "make_file", "make_mac_address", "make_name", @@ -185,26 +188,58 @@ def patch(self, obj, attribute, value=mock.sentinel.unset): return value -class AsyncMock(mock.Mock): - """Mock that is "future-like"; see PEP-492 for the details. +class AsyncAwaitableMock(mock.Mock): + """Mock that is "future-like"; see PEP-492. The new `await` syntax chokes on arguments that are not future-like, i.e. have an `__await__` call, so we have to fool it. + + This passes calls to `__await__` through to `__call__`. + """ + + async def __await__(_mock_self, *args, **kwargs): + return super().__call__(*args, **kwargs) + + +class AsyncCallableMock(mock.Mock): + """Mock which ensures calls are "future-like"; see PEP-492. + + As in, calls to this mock return `return_value` or `side_effect` as usual, + but these are awaitable, or native coroutines. """ - def __call__(_mock_self, *args, **kwargs): - callup = super(AsyncMock, _mock_self).__call__ - call = partial(callup, *args, **kwargs) - return Awaitable(call) + async def __call__(_mock_self, *args, **kwargs): + return super().__call__(*args, **kwargs) + + +class AsyncContextMock(mock.Mock): + """Mock that acts as an async context manager; see PEP-492. + It's not enough to mock `__aenter__` and `__aexit__` because Python + obtains these callable attributes from the context manager's *type*. See + https://www.python.org/dev/peps/pep-0492/#new-syntax. This is consistent + with how non-asynchronous context managers work, but it's counterintuitive + nonetheless. -class Awaitable: - """Wrap a "normal" call in a future-like object.""" + This returns itself from `__aenter__` and `None` from `__aexit__`. + """ + + async def __aenter__(_mock_self): + return _mock_self + + async def __aexit__(_mock_self, *exc_info): + return None + + +class AsyncIterableMock(mock.Mock): + """Mock that can be asynchronously iterated; see PEP-492. + + This returns itself from `__aiter__` and passes through calls to + `__anext__` to `__call__`. + """ - def __init__(self, call): - super(Awaitable, self).__init__() - self._call = call + def __aiter__(_mock_self): + return _mock_self - def __await__(self): - yield # This serves only to make this a generator. - return self._call() + async def __anext__(_mock_self): + return super().__call__() diff --git a/maas/client/viscera/boot_resources.py b/maas/client/viscera/boot_resources.py index dfe616c..cf9b222 100644 --- a/maas/client/viscera/boot_resources.py +++ b/maas/client/viscera/boot_resources.py @@ -214,17 +214,17 @@ async def _put_chunk( utils.sign(upload_uri, headers, credentials) # Perform upload of chunk. - response = await session.put( - upload_uri, data=buf, headers=headers) - if response.status != 200: - content = await response.read() - request = { - "body": buf, - "headers": headers, - "method": "PUT", - "uri": upload_uri, - } - raise CallError(request, response, content, None) + async with await session.put( + upload_uri, data=buf, headers=headers) as response: + if response.status != 200: + content = await response.read() + request = { + "body": buf, + "headers": headers, + "method": "PUT", + "uri": upload_uri, + } + raise CallError(request, response, content, None) class BootResources(ObjectSet, metaclass=BootResourcesType): diff --git a/maas/client/viscera/testing.py b/maas/client/viscera/testing.py index c1ffd21..80578c4 100644 --- a/maas/client/viscera/testing.py +++ b/maas/client/viscera/testing.py @@ -9,7 +9,7 @@ from unittest.mock import Mock from . import OriginBase -from ..testing import AsyncMock +from ..testing import AsyncCallableMock def bind(*objects, session=None): @@ -42,7 +42,7 @@ def _flatten_to_items(thing): if session is None: session = Mock(name="session") session.handlers = { - name: AsyncMock(name="handler(%s)" % name) + name: AsyncCallableMock(name="handler(%s)" % name) for name in objects } diff --git a/maas/client/viscera/tests/test_boot_resources.py b/maas/client/viscera/tests/test_boot_resources.py index 3499164..f730204 100644 --- a/maas/client/viscera/tests/test_boot_resources.py +++ b/maas/client/viscera/tests/test_boot_resources.py @@ -13,6 +13,7 @@ ) import aiohttp +from aiohttp.test_utils import make_mocked_coro from testtools.matchers import ( Equals, MatchesDict, @@ -21,7 +22,8 @@ from .. import boot_resources from ...testing import ( - AsyncMock, + AsyncCallableMock, + AsyncContextMock, make_name_without_spaces, make_string, pick_bool, @@ -363,9 +365,10 @@ def test__create_uploads_in_chunks_and_reloads_resource(self): mock_sign = self.patch(boot_resources.utils, "sign") # Mock ClientSession.put as the create does PUT directly to the API. - put = AsyncMock() - response = put.return_value = AsyncMock(spec=aiohttp.ClientResponse) + response = AsyncContextMock(spec=aiohttp.ClientResponse) response.status = HTTPStatus.OK.value + + put = AsyncCallableMock(return_value=response) self.patch(boot_resources.aiohttp.ClientSession, "put", put) # Progress handler called on each chunk. @@ -373,9 +376,8 @@ def test__create_uploads_in_chunks_and_reloads_resource(self): # Create and upload the resource. resource = BootResources.create( - name, architecture, buf, - title=title, filetype=filetype, chunk_size=chunk_size, - progress_callback=progress_handler) + name, architecture, buf, title=title, filetype=filetype, + chunk_size=chunk_size, progress_callback=progress_handler) # Check that returned resource is correct and updated. self.assertThat(resource, MatchesStructure.byEquality( @@ -466,16 +468,17 @@ def test__create_raises_CallError_on_chunk_upload_failure(self): mock_sign = self.patch(boot_resources.utils, "sign") # Mock ClientSession.put as the create does PUT directly to the API. - put = AsyncMock() - response = put.return_value = AsyncMock(spec=aiohttp.ClientResponse) + response = AsyncContextMock(spec=aiohttp.ClientResponse) response.status = HTTPStatus.INTERNAL_SERVER_ERROR.value - response.read.return_value = b"Error" + response.read = make_mocked_coro(b"Error") + + put = AsyncCallableMock(return_value=response) self.patch(boot_resources.aiohttp.ClientSession, "put", put) self.assertRaises( - boot_resources.CallError, BootResources.create, - name, architecture, buf, - title=title, filetype=filetype, chunk_size=chunk_size) + boot_resources.CallError, BootResources.create, name, + architecture, buf, title=title, filetype=filetype, + chunk_size=chunk_size) # Check that the request was signed. self.assertTrue(mock_sign.called) From 3ac461f22c186768ed06785d35c94a904414d93b Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 28 Feb 2017 17:35:45 +0100 Subject: [PATCH 019/245] Tweak coverage measuring and reporting configuration. --- .coveragerc | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..216dfef --- /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 From bea99fcbfdcd9d7b32abf446de7e621668df602f Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 28 Feb 2017 18:10:10 +0100 Subject: [PATCH 020/245] Use the exact namespace package snippet as recommended by setuptools' docs. --- maas/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/maas/__init__.py b/maas/__init__.py index ece379c..de40ea7 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__) From 79ff503bba0fdaa2fdcbc20267690c80127b1dff Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 28 Feb 2017 18:12:14 +0100 Subject: [PATCH 021/245] Beginnings of the integration test suite. --- Makefile | 6 ++- integrate/__init__.py | 0 integrate/__main__.py | 7 +++ integrate/test.py | 111 ++++++++++++++++++++++++++++++++++++++++++ tox.ini | 9 ++++ 5 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 integrate/__init__.py create mode 100644 integrate/__main__.py create mode 100644 integrate/test.py diff --git a/Makefile b/Makefile index 83053c0..4523247 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ upload: bin/python setup.py README test: bin/tox @bin/tox +integrate: bin/tox + @bin/tox -e integrate + lint: bin/tox @bin/tox -e lint @@ -25,6 +28,7 @@ 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 # --- @@ -47,4 +51,4 @@ bin/mkdocs: bin/pip # --- -.PHONY: develop dist docs test lint clean +.PHONY: develop dist docs test integrate lint clean diff --git a/integrate/__init__.py b/integrate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/integrate/__main__.py b/integrate/__main__.py new file mode 100644 index 0000000..a386448 --- /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 0000000..b03870b --- /dev/null +++ b/integrate/test.py @@ -0,0 +1,111 @@ +"""Integration tests for `maas.client`.""" + +from http import HTTPStatus +import io +from itertools import repeat +import random + +from maas.client import ( + bones, + viscera, +) +from maas.client.testing import ( + make_name_without_spaces, + TestCase, +) +from maas.client.utils import ( + creds, + profiles, +) +from testtools.matchers import ( + AllMatch, + Equals, + IsInstance, + MatchesAll, + 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): + """Tests for module functions.""" + + 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)), + )) + + 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))) + + +# TestBootSources +# TestBootSourceSelections +# TestControllers +# 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)) + + +# TestFiles +# TestMAAS +# TestMachines +# TestTags +# TestTesting +# TestUsers +# TestVersion +# TestZones + + +# End. diff --git a/tox.ini b/tox.ini index 6b7ea68..e10242a 100644 --- a/tox.ini +++ b/tox.ini @@ -6,6 +6,15 @@ commands = coverage run setup.py test {posargs} sitepackages = False deps = coverage +[testenv:integrate] +commands = {envpython} -m integrate {posargs} +sitepackages = False +usedevelop = True +deps = + fixtures + testscenarios + testtools + [testenv:lint] commands = flake8 maas --isolated --ignore=E402,E123,E731 sitepackages = False From 60e60de42c81373aec69081c8e5c8fa6bb96f86a Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 28 Feb 2017 18:14:28 +0100 Subject: [PATCH 022/245] Update CallError to work with aiohttp. --- maas/client/bones/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/maas/client/bones/__init__.py b/maas/client/bones/__init__.py index 81a79a8..12f5a1b 100644 --- a/maas/client/bones/__init__.py +++ b/maas/client/bones/__init__.py @@ -326,7 +326,7 @@ def __init__(self, request, response, content, call): @property def status(self): - return int(self.response["status"]) + return self.response.status class CallAPI: From a67509c3eccb0895da9fd8b65f7bf2aa0d0cfdc7 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 13:56:27 +0100 Subject: [PATCH 023/245] New utility function, coalesce, similar to PostgreSQL's. --- maas/client/utils/__init__.py | 15 +++++++++++++++ maas/client/utils/tests/test.py | 10 ++++++++++ 2 files changed, 25 insertions(+) diff --git a/maas/client/utils/__init__.py b/maas/client/utils/__init__.py index 19f3b8e..8d6324c 100644 --- a/maas/client/utils/__init__.py +++ b/maas/client/utils/__init__.py @@ -2,6 +2,7 @@ __all__ = [ "api_url", + "coalesce", "get_all_subclasses", "parse_docstring", "prepare_payload", @@ -287,6 +288,20 @@ def gen_retries(start, end, intervals, time=time): break +def coalesce(*values, default=None): + """Return the first argument that is not `None`. + + If all arguments are `None`, return `default`, which is `None` by default. + + Similar to PostgreSQL's `COALESCE` function. + """ + for value in values: + if value is not None: + return value + else: + return default + + class Spinner: """Display a spinner at the terminal, if it's a TTY. diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index eff2d71..7d504d0 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -12,6 +12,7 @@ from testtools.matchers import ( AfterPreprocessing, Equals, + Is, MatchesListwise, ) from twisted.internet.task import Clock @@ -322,6 +323,15 @@ def test_api_url(self): ] self.assertThat(urls, MatchesListwise(expected)) + def test_coalesce(self): + self.assertThat(utils.coalesce("abc"), Equals("abc")) + self.assertThat(utils.coalesce(None, "abc"), Equals("abc")) + self.assertThat(utils.coalesce("abc", None), Equals("abc")) + self.assertThat(utils.coalesce("abc", "def"), Equals("abc")) + self.assertThat(utils.coalesce(default="foo"), Equals("foo")) + self.assertThat(utils.coalesce(None, default="foo"), Equals("foo")) + self.assertThat(utils.coalesce(), Is(None)) + class TestRetries(TestCase): From 5438ca8890e267cd41b46b8e4d589dcf93f7fff1 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 13:57:42 +0100 Subject: [PATCH 024/245] Leave validation of keyring_filename and keyring_data to the server. --- maas/client/viscera/boot_sources.py | 14 +++----------- maas/client/viscera/tests/test_boot_sources.py | 10 ---------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/maas/client/viscera/boot_sources.py b/maas/client/viscera/boot_sources.py index 05b8f7c..7687f11 100644 --- a/maas/client/viscera/boot_sources.py +++ b/maas/client/viscera/boot_sources.py @@ -13,6 +13,7 @@ ObjectType, parse_timestamp, ) +from ..utils import coalesce class BootSourcesType(ObjectType): @@ -20,18 +21,9 @@ class BootSourcesType(ObjectType): async def create(cls, url, *, keyring_filename=None, keyring_data=None): """Create a new `BootSource`.""" - if (not url.endswith(".json") and - keyring_filename is None and - keyring_data is None): - raise ValueError( - "Either keyring_filename and keyring_data must be set when " - "providing a signed source.") data = await cls._handler.create( - url=url, - keyring_filename=( - "" if keyring_filename is None else keyring_filename), - keyring_data=( - "" if keyring_data is None else keyring_data)) + url=url, keyring_filename=coalesce(keyring_filename, ""), + keyring_data=coalesce(keyring_data, "")) return cls._object(data) async def read(cls): diff --git a/maas/client/viscera/tests/test_boot_sources.py b/maas/client/viscera/tests/test_boot_sources.py index b2f7b79..56f7bab 100644 --- a/maas/client/viscera/tests/test_boot_sources.py +++ b/maas/client/viscera/tests/test_boot_sources.py @@ -86,16 +86,6 @@ def test__read(self): sources = BootSources.read() self.assertEquals(2, len(sources)) - def test__create_raises_ValueError_when_signed(self): - url = "http://images.maas.io/ephemeral-v3/daily/" - - BootSources = make_origin().BootSources - - error = self.assertRaises(ValueError, BootSources.create, url) - self.assertEquals( - "Either keyring_filename and keyring_data must be set when " - "providing a signed source.", str(error)) - def test__create_calls_create_with_keyring_filename(self): source_id = random.randint(0, 100) url = "http://images.maas.io/ephemeral-v3/daily/" From b0665b79d9ef62094239bffad2d34eecf3ff1001 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 14:07:00 +0100 Subject: [PATCH 025/245] In a couple of the async mocks, just call self; no need for up-calling. --- maas/client/testing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/maas/client/testing.py b/maas/client/testing.py index 413de3d..5cdbe75 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -198,7 +198,7 @@ class AsyncAwaitableMock(mock.Mock): """ async def __await__(_mock_self, *args, **kwargs): - return super().__call__(*args, **kwargs) + return _mock_self(*args, **kwargs) class AsyncCallableMock(mock.Mock): @@ -242,4 +242,4 @@ def __aiter__(_mock_self): return _mock_self async def __anext__(_mock_self): - return super().__call__() + return _mock_self() From d599e29f3e341c2770f38838bd611e82eb0ccb66 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 14:07:40 +0100 Subject: [PATCH 026/245] Tests for creating and deleteing boot sources. --- integrate/test.py | 32 +++++++++++++++++++++++++---- maas/client/viscera/boot_sources.py | 9 +++++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/integrate/test.py b/integrate/test.py index b03870b..405d573 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -49,7 +49,6 @@ def setUp(self): class TestAccount(IntegrationTestCase): - """Tests for module functions.""" def test__create_and_delete_credentials(self): credentials = self.origin.Account.create_credentials() @@ -75,13 +74,38 @@ def test__create_and_delete_boot_resource(self): self.assertThat(boot_resource, IsInstance(self.origin.BootResource)) boot_resource.delete() error = self.assertRaises( - bones.CallError, - self.origin.BootResource.read, boot_resource.id) + 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))) -# TestBootSources # TestBootSourceSelections # TestControllers # TestDevices diff --git a/maas/client/viscera/boot_sources.py b/maas/client/viscera/boot_sources.py index 7687f11..f0933c8 100644 --- a/maas/client/viscera/boot_sources.py +++ b/maas/client/viscera/boot_sources.py @@ -20,7 +20,14 @@ class BootSourcesType(ObjectType): """Metaclass for `BootSources`.""" async def create(cls, url, *, keyring_filename=None, keyring_data=None): - """Create a new `BootSource`.""" + """Create a new `BootSource`. + + :param url: The URL for the boot source. + :param keyring_filename: The path to the keyring file on the server. + :param keyring_data: The GPG keyring data, binary. as a file-like + object. For example: an open file handle in binary mode, or an + instance of `io.BytesIO`. + """ data = await cls._handler.create( url=url, keyring_filename=coalesce(keyring_filename, ""), keyring_data=coalesce(keyring_data, "")) From 0e3fed870c9c26c764fff1ed456a67a610197509 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 14:14:09 +0100 Subject: [PATCH 027/245] List boot sources. --- integrate/test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/integrate/test.py b/integrate/test.py index 405d573..2170e6a 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -1,5 +1,6 @@ """Integration tests for `maas.client`.""" +from datetime import datetime from http import HTTPStatus import io from itertools import repeat @@ -105,6 +106,24 @@ def test__create_and_delete_source_with_keyring_data(self): 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 # TestControllers From 4843760080cec2bc25031109155cf318e9b80f3f Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 14:35:05 +0100 Subject: [PATCH 028/245] Test the attributes of object retrieved from the API. --- integrate/test.py | 54 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/integrate/test.py b/integrate/test.py index 2170e6a..fdfff49 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -1,5 +1,6 @@ """Integration tests for `maas.client`.""" +from collections import Mapping from datetime import datetime from http import HTTPStatus import io @@ -21,8 +22,10 @@ from testtools.matchers import ( AllMatch, Equals, + Is, IsInstance, MatchesAll, + MatchesAny, MatchesStructure, ) @@ -65,6 +68,17 @@ def test__list_boot_resources(self): 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") @@ -113,16 +127,16 @@ def test__list_boot_sources(self): 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), - ), - )) + 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 @@ -140,6 +154,20 @@ def test__query_events(self): 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 @@ -151,4 +179,10 @@ def test__query_events(self): # TestZones +# Additional matchers. + +def Optional(matcher, default=Is(None)): + return MatchesAny(matcher, default) + + # End. From 26a29370eca581010d6785c07c690fc6fdbd9f5f Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 15:22:35 +0100 Subject: [PATCH 029/245] List, allocate, deploy, and release machines. --- integrate/test.py | 74 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/integrate/test.py b/integrate/test.py index fdfff49..f230e17 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -6,6 +6,7 @@ import io from itertools import repeat import random +from time import sleep from maas.client import ( bones, @@ -18,6 +19,7 @@ from maas.client.utils import ( creds, profiles, + retries, ) from testtools.matchers import ( AllMatch, @@ -171,7 +173,77 @@ def test__events(self): # TestFiles # TestMAAS -# TestMachines + + +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 test__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")) + + # TestTags # TestTesting # TestUsers From bb87888092eac14d7bc07dcd65321e4407b6cf4c Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 16:41:19 +0100 Subject: [PATCH 030/245] Rename TestCase.make_file to makeFile and .make_dir to makeDir, and remove the free-standing make_file function. --- maas/client/testing.py | 64 ++++++++++------------- maas/client/utils/tests/test.py | 2 +- maas/client/utils/tests/test_multipart.py | 4 +- maas/client/utils/tests/test_profiles.py | 8 +-- 4 files changed, 35 insertions(+), 43 deletions(-) diff --git a/maas/client/testing.py b/maas/client/testing.py index 5cdbe75..35190b3 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -5,7 +5,6 @@ "AsyncCallableMock", "AsyncContextMock", "AsyncIterableMock", - "make_file", "make_mac_address", "make_name", "make_name_without_spaces", @@ -79,32 +78,6 @@ def make_name_without_spaces(prefix="name", sep='-', size=6): return prefix + sep + make_string_without_spaces(size) -def make_file(location, name=None, contents=None): - """Create a file, and write data to it. - - Prefer the eponymous convenience wrapper in - :class:`maastesting.testcase.MAASTestCase`. It creates a temporary - directory and arranges for its eventual cleanup. - - :param location: Directory. Use a temporary directory for this, and - make sure it gets cleaned up after the test! - :param name: Optional name for the file. If none is given, one will - be made up. - :param contents: Optional contents for the file. If omitted, some - arbitrary ASCII text will be written. - :type contents: unicode, but containing only ASCII characters. - :return: Path to the file. - """ - if name is None: - name = make_string() - if contents is None: - contents = make_string().encode('ascii') - filename = path.join(location, name) - with open(filename, 'wb') as f: - f.write(contents) - return filename - - def make_mac_address(delimiter=":"): """Make a MAC address string with the given delimiter.""" octets = islice(random_octets, 6) @@ -140,22 +113,41 @@ def setUp(self): self.addCleanup(self.loop.close) asyncio.set_event_loop(self.loop) - def make_dir(self): + def makeDir(self): """Create a temporary directory. - This is a convenience wrapper around a fixture incantation. That's - the only reason why it's on the test case and not in a factory. + This creates a new temporary directory. This will be removed during + test tear-down. + + :return: The path to the directory. """ return self.useFixture(TempDir()).path - def make_file(self, name=None, contents=None): - """Create, and write to, a file. + def makeFile(self, name=None, contents=None, location=None): + """Create a file, and write data to it. + + This creates a new file `name` in `location` and fills it with + `contents`. This file will be removed during test tear-down. + + :param name: Name for the file; optional. If omitted, a random name + will be chosen. + :param contents: Contents for the file; optional. If omitted, some + arbitrary ASCII text will be written. + :param location: Path to a directory; optional. If omitted, a new + temporary directory will be created with `makeDir`. - This is a convenience wrapper around `make_dir` and a factory - call. It ensures that the file is in a directory that will be - cleaned up at the end of the test. + :return: The path to the file. """ - return make_file(self.make_dir(), name, contents) + if name is None: + name = make_string() + if contents is None: + contents = make_string().encode('ascii') + if location is None: + location = self.makeDir() + filename = path.join(location, name) + with open(filename, 'wb') as f: + f.write(contents) + return filename def assertDocTestMatches(self, expected, observed, flags=None): """See if `observed` matches `expected`, a doctest sample. diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index 7d504d0..d078268 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -214,7 +214,7 @@ class TestPayloadPreparationWithFiles(TestCase): def test_files_are_included(self): parameter = make_string() contents = os.urandom(5) - filename = self.make_file(contents=contents) + filename = self.makeFile(contents=contents) # Writing the parameter as "parameter@=filename" on the # command-line causes name_value_pair() to return a `name, # opener` tuple, where `opener` is a callable that returns an diff --git a/maas/client/utils/tests/test_multipart.py b/maas/client/utils/tests/test_multipart.py index 6bc2006..0f59245 100644 --- a/maas/client/utils/tests/test_multipart.py +++ b/maas/client/utils/tests/test_multipart.py @@ -117,8 +117,8 @@ def test_encode_multipart_data_multiple_params(self): ] files = [ BytesIO(b"f1"), - open(self.make_file(contents=b"f2"), "rb"), - open(self.make_file(contents=b"f3"), "rb"), + open(self.makeFile(contents=b"f2"), "rb"), + open(self.makeFile(contents=b"f3"), "rb"), ] for fd in files: self.addCleanup(fd.close) diff --git a/maas/client/utils/tests/test_profiles.py b/maas/client/utils/tests/test_profiles.py index f8805f3..846cb75 100644 --- a/maas/client/utils/tests/test_profiles.py +++ b/maas/client/utils/tests/test_profiles.py @@ -146,7 +146,7 @@ def test_removing_profile(self): def test_open_and_close(self): # ProfileStore.open() returns a context manager that closes the # database on exit. - config_file = os.path.join(self.make_dir(), "config") + config_file = os.path.join(self.makeDir(), "config") config = ProfileStore.open(config_file) self.assertIsInstance(config, contextlib._GeneratorContextManager) with config as config: @@ -160,7 +160,7 @@ def test_open_and_close(self): def test_open_permissions_new_database(self): # ProfileStore.open() applies restrictive file permissions to newly # created configuration databases. - config_file = os.path.join(self.make_dir(), "config") + config_file = os.path.join(self.makeDir(), "config") with ProfileStore.open(config_file): perms = FilePath(config_file).getPermissions() self.assertEqual("rw-------", perms.shorthand()) @@ -168,7 +168,7 @@ def test_open_permissions_new_database(self): def test_open_permissions_existing_database(self): # ProfileStore.open() leaves the file permissions of existing # configuration databases. - config_file = os.path.join(self.make_dir(), "config") + config_file = os.path.join(self.makeDir(), "config") open(config_file, "wb").close() # touch. os.chmod(config_file, 0o644) # u=rw,go=r with ProfileStore.open(config_file): @@ -176,7 +176,7 @@ def test_open_permissions_existing_database(self): self.assertEqual("rw-r--r--", perms.shorthand()) def test_open_does_one_time_migration(self): - home = self.make_dir() + home = self.makeDir() dbpath_old = os.path.join(home, ".maascli.db") dbpath_new = os.path.join(home, ".maas.db") From 4dd16edeffcb61c1942a7256db90e48bbd832ca0 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 17:16:14 +0100 Subject: [PATCH 031/245] Rename randrange to make_range to avoid confusion with random.randrange. --- maas/client/testing.py | 12 ++++++------ maas/client/viscera/tests/test_events.py | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/maas/client/testing.py b/maas/client/testing.py index 35190b3..54e5e0b 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -8,10 +8,10 @@ "make_mac_address", "make_name", "make_name_without_spaces", + "make_range", "make_string", "make_string_without_spaces", "pick_bool", - "randrange", "TestCase", ] @@ -84,16 +84,16 @@ def make_mac_address(delimiter=":"): return delimiter.join(format(octet, "02x") for octet in octets) +def make_range(cmin=1, cmax=9): + """Return a range of random length between `cmin` and `cmax`.""" + return range(random.randint(cmin, cmax)) + + def pick_bool(): """Return either `True` or `False` at random.""" return random.choice((True, False)) -def randrange(cmin=1, cmax=9): - """Yield a random number of times between `cmin` and `cmax`.""" - return range(random.randint(cmin, cmax)) - - class WithScenarios(testscenarios.WithScenarios): """Variant of testscenarios_' that provides ``__call__``.""" diff --git a/maas/client/viscera/tests/test_events.py b/maas/client/viscera/tests/test_events.py index 00d38bb..01b5894 100644 --- a/maas/client/viscera/tests/test_events.py +++ b/maas/client/viscera/tests/test_events.py @@ -19,7 +19,7 @@ from ...testing import ( make_mac_address, make_name_without_spaces, - randrange, + make_range, TestCase, ) from ..testing import bind @@ -160,12 +160,12 @@ def test__next_requests_page_of_newer_events(self): def test__forwards_returns_a_continuous_iterator(self): pages = [ { - "events": [make_Event_dict() for _ in randrange()], + "events": [make_Event_dict() for _ in make_range()], "prev_uri": "?going=backwards", "next_uri": "?going=forwards", }, { - "events": [make_Event_dict() for _ in randrange()], + "events": [make_Event_dict() for _ in make_range()], "prev_uri": "?going=backwards", "next_uri": "?going=forwards", }, @@ -188,12 +188,12 @@ def test__forwards_returns_a_continuous_iterator(self): def test__backwards_returns_a_continuous_iterator(self): pages = [ { - "events": [make_Event_dict() for _ in randrange()], + "events": [make_Event_dict() for _ in make_range()], "prev_uri": "?going=backwards", "next_uri": "?going=forwards", }, { - "events": [make_Event_dict() for _ in randrange()], + "events": [make_Event_dict() for _ in make_range()], "prev_uri": "?going=backwards", "next_uri": "?going=forwards", }, From 29a2a80371cf198618d86d88a98b7ee47f23e864 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 17:20:20 +0100 Subject: [PATCH 032/245] Return pathlib.Path instances from makeDir and makeFile. --- maas/client/testing.py | 28 +++++++++---------- maas/client/utils/profiles.py | 24 +++++++--------- maas/client/utils/tests/test.py | 4 +-- maas/client/utils/tests/test_multipart.py | 4 +-- maas/client/utils/tests/test_profiles.py | 34 ++++++++++++----------- 5 files changed, 46 insertions(+), 48 deletions(-) diff --git a/maas/client/testing.py b/maas/client/testing.py index 54e5e0b..73f52cd 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -22,7 +22,7 @@ islice, repeat, ) -from os import path +from pathlib import Path import random import string from unittest import mock @@ -119,9 +119,10 @@ def makeDir(self): This creates a new temporary directory. This will be removed during test tear-down. - :return: The path to the directory. + :return: The path to the directory, as a `pathlib.Path`. """ - return self.useFixture(TempDir()).path + tempdir = self.useFixture(TempDir()) + return Path(tempdir.path) def makeFile(self, name=None, contents=None, location=None): """Create a file, and write data to it. @@ -132,22 +133,21 @@ def makeFile(self, name=None, contents=None, location=None): :param name: Name for the file; optional. If omitted, a random name will be chosen. :param contents: Contents for the file; optional. If omitted, some - arbitrary ASCII text will be written. + arbitrary text will be written. :param location: Path to a directory; optional. If omitted, a new temporary directory will be created with `makeDir`. - :return: The path to the file. + :return: The path to the file, as a `pathlib.Path`. """ - if name is None: - name = make_string() + location = self.makeDir() if location is None else Path(location) + filepath = location.joinpath(make_string() if name is None else name) + if contents is None: - contents = make_string().encode('ascii') - if location is None: - location = self.makeDir() - filename = path.join(location, name) - with open(filename, 'wb') as f: - f.write(contents) - return filename + filepath.write_text(make_string()) + else: + filepath.write_bytes(contents) + + return filepath def assertDocTestMatches(self, expected, observed, flags=None): """See if `observed` matches `expected`, a doctest sample. diff --git a/maas/client/utils/profiles.py b/maas/client/utils/profiles.py index 8abf95a..68e00ef 100644 --- a/maas/client/utils/profiles.py +++ b/maas/client/utils/profiles.py @@ -9,13 +9,7 @@ from contextlib import contextmanager from copy import deepcopy import json -import os -from os.path import ( - exists, - expanduser, - isfile, - samefile, -) +from pathlib import Path import sqlite3 from textwrap import dedent from typing import ( @@ -161,7 +155,7 @@ def schema_import(conn, dbpath): :param dbpath: The filesystem path to the source SQLite3 database. """ conn.execute( - "ATTACH DATABASE ? AS source", (dbpath,)) + "ATTACH DATABASE ? AS source", (str(dbpath),)) conn.execute( "INSERT OR IGNORE INTO profiles (name, data)" " SELECT name, data FROM source.profiles" @@ -244,7 +238,7 @@ def default(self): @classmethod @contextmanager - def open(cls, dbpath=expanduser("~/.maas.db")): + def open(cls, dbpath=Path("~/.maas.db").expanduser()): """Load a profiles database. Called without arguments this will open (and create) a database in the @@ -255,15 +249,17 @@ def open(cls, dbpath=expanduser("~/.maas.db")): :param dbpath: The path to the database file to create and open. """ + # Ensure we're working with a Path instance. + dbpath = Path(dbpath) # See if we ought to do a one-time migration. - migrate_from = expanduser("~/.maascli.db") - migrate = isfile(migrate_from) and not exists(dbpath) + migrate_from = Path("~/.maascli.db").expanduser() + migrate = migrate_from.is_file() and not dbpath.exists() # Initialise filename with restrictive permissions... - os.close(os.open(dbpath, os.O_CREAT | os.O_APPEND, 0o600)) + dbpath.touch(mode=0o600, exist_ok=True) # Final check to see if it's safe to migrate. - migrate = migrate and not samefile(migrate_from, dbpath) + migrate = migrate and not migrate_from.samefile(dbpath) # before opening it with sqlite. - database = sqlite3.connect(dbpath) + database = sqlite3.connect(str(dbpath)) try: store = cls(database) if migrate: diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index d078268..81c95f4 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -214,12 +214,12 @@ class TestPayloadPreparationWithFiles(TestCase): def test_files_are_included(self): parameter = make_string() contents = os.urandom(5) - filename = self.makeFile(contents=contents) + filepath = self.makeFile(contents=contents) # Writing the parameter as "parameter@=filename" on the # command-line causes name_value_pair() to return a `name, # opener` tuple, where `opener` is a callable that returns an # open file handle. - data = [(parameter, partial(open, filename, "rb"))] + data = [(parameter, partial(filepath.open, "rb"))] uri, body, headers = utils.prepare_payload( op=None, method="POST", uri="http://localhost", data=data) diff --git a/maas/client/utils/tests/test_multipart.py b/maas/client/utils/tests/test_multipart.py index 0f59245..d611532 100644 --- a/maas/client/utils/tests/test_multipart.py +++ b/maas/client/utils/tests/test_multipart.py @@ -117,8 +117,8 @@ def test_encode_multipart_data_multiple_params(self): ] files = [ BytesIO(b"f1"), - open(self.makeFile(contents=b"f2"), "rb"), - open(self.makeFile(contents=b"f3"), "rb"), + self.makeFile(contents=b"f2").open("rb"), + self.makeFile(contents=b"f3").open("rb"), ] for fd in files: self.addCleanup(fd.close) diff --git a/maas/client/utils/tests/test_profiles.py b/maas/client/utils/tests/test_profiles.py index 846cb75..aca21c1 100644 --- a/maas/client/utils/tests/test_profiles.py +++ b/maas/client/utils/tests/test_profiles.py @@ -3,8 +3,7 @@ __all__ = [] import contextlib -import os -import os.path +from pathlib import Path import sqlite3 from testtools.matchers import ( @@ -146,7 +145,7 @@ def test_removing_profile(self): def test_open_and_close(self): # ProfileStore.open() returns a context manager that closes the # database on exit. - config_file = os.path.join(self.makeDir(), "config") + config_file = self.makeDir().joinpath("config") config = ProfileStore.open(config_file) self.assertIsInstance(config, contextlib._GeneratorContextManager) with config as config: @@ -160,33 +159,36 @@ def test_open_and_close(self): def test_open_permissions_new_database(self): # ProfileStore.open() applies restrictive file permissions to newly # created configuration databases. - config_file = os.path.join(self.makeDir(), "config") + config_file = self.makeDir().joinpath("config") with ProfileStore.open(config_file): - perms = FilePath(config_file).getPermissions() + perms = FilePath(str(config_file)).getPermissions() self.assertEqual("rw-------", perms.shorthand()) def test_open_permissions_existing_database(self): # ProfileStore.open() leaves the file permissions of existing # configuration databases. - config_file = os.path.join(self.makeDir(), "config") - open(config_file, "wb").close() # touch. - os.chmod(config_file, 0o644) # u=rw,go=r + config_file = self.makeDir().joinpath("config") + config_file.touch() + config_file.chmod(0o644) # u=rw,go=r with ProfileStore.open(config_file): - perms = FilePath(config_file).getPermissions() + perms = FilePath(str(config_file)).getPermissions() self.assertEqual("rw-r--r--", perms.shorthand()) def test_open_does_one_time_migration(self): home = self.makeDir() - dbpath_old = os.path.join(home, ".maascli.db") - dbpath_new = os.path.join(home, ".maas.db") + dbpath_old = home.joinpath(".maascli.db") + dbpath_new = home.joinpath(".maas.db") + # Path.expanduser() is used by ProfileStore.open(). We expect the + # paths to be expanded to be one of those below. def expanduser(path): - # We expect the paths to be expanded to be one of those below. - paths = {"~/.maas.db": dbpath_new, "~/.maascli.db": dbpath_old} - return paths[path] + if path == Path("~/.maas.db"): + return dbpath_new + if path == Path("~/.maascli.db"): + return dbpath_old + raise ValueError(path) - # expanduser() is used by ProfileStore.open(). - self.patch(profiles, "expanduser", expanduser) + self.patch(profiles.Path, "expanduser", expanduser) # A profile that will be migrated. profile = make_profile() From 97ce377334dd37ab3a6e43552e56bafee1ecc4ca Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 1 Mar 2017 17:24:35 +0100 Subject: [PATCH 033/245] Add make_bytes and use it in TestCase.makeFile. --- maas/client/testing.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/maas/client/testing.py b/maas/client/testing.py index 73f52cd..159a4d7 100644 --- a/maas/client/testing.py +++ b/maas/client/testing.py @@ -5,6 +5,7 @@ "AsyncCallableMock", "AsyncContextMock", "AsyncIterableMock", + "make_bytes", "make_mac_address", "make_name", "make_name_without_spaces", @@ -78,6 +79,11 @@ def make_name_without_spaces(prefix="name", sep='-', size=6): return prefix + sep + make_string_without_spaces(size) +def make_bytes(size=10): + """Make a random byte string.""" + return bytes(islice(random_octets, size)) + + def make_mac_address(delimiter=":"): """Make a MAC address string with the given delimiter.""" octets = islice(random_octets, 6) @@ -133,7 +139,7 @@ def makeFile(self, name=None, contents=None, location=None): :param name: Name for the file; optional. If omitted, a random name will be chosen. :param contents: Contents for the file; optional. If omitted, some - arbitrary text will be written. + arbitrary bytes will be written. :param location: Path to a directory; optional. If omitted, a new temporary directory will be created with `makeDir`. @@ -141,12 +147,7 @@ def makeFile(self, name=None, contents=None, location=None): """ location = self.makeDir() if location is None else Path(location) filepath = location.joinpath(make_string() if name is None else name) - - if contents is None: - filepath.write_text(make_string()) - else: - filepath.write_bytes(contents) - + filepath.write_bytes(make_bytes() if contents is None else contents) return filepath def assertDocTestMatches(self, expected, observed, flags=None): From c64cfed854992e91b75180603e900d5a2811159c Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 27 Feb 2017 17:09:16 +0100 Subject: [PATCH 034/245] Facade for account and boot_resources. --- maas/client/_client.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/maas/client/_client.py b/maas/client/_client.py index 8b84340..9964341 100644 --- a/maas/client/_client.py +++ b/maas/client/_client.py @@ -70,6 +70,23 @@ def __init__(self, origin): super(Client, self).__init__() self._origin = origin + @facade + def account(origin): + return { + "create_credentials": origin.Account.create_credentials, + "delete_credentials": origin.Account.delete_credentials, + } + + @facade + def boot_resources(origin): + return { + "create": origin.BootResources.create, + "get": origin.BootResource.read, + "list": origin.BootResources.read, + "start_import": origin.BootResources.start_import, + "stop_import": origin.BootResources.stop_import, + } + @facade def machines(origin): return { From 8a94ab85e3c74f04c80506c9d9391f8ca5e173c0 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Fri, 3 Mar 2017 16:57:38 +0100 Subject: [PATCH 035/245] Remove several unused *NotFound exceptions. --- maas/client/viscera/controllers.py | 4 ---- maas/client/viscera/devices.py | 4 ---- maas/client/viscera/zones.py | 4 ---- 3 files changed, 12 deletions(-) diff --git a/maas/client/viscera/controllers.py b/maas/client/viscera/controllers.py index d657650..a15915a 100644 --- a/maas/client/viscera/controllers.py +++ b/maas/client/viscera/controllers.py @@ -26,10 +26,6 @@ async def read(cls): return cls(map(cls._object, data)) -class RackControllerNotFound(Exception): - """Rack-controller was not found.""" - - class RackControllers(ObjectSet, metaclass=RackControllersType): """The set of rack-controllers stored in MAAS.""" diff --git a/maas/client/viscera/devices.py b/maas/client/viscera/devices.py index c9367b4..e5a4f95 100644 --- a/maas/client/viscera/devices.py +++ b/maas/client/viscera/devices.py @@ -25,10 +25,6 @@ async def read(cls): return cls(map(cls._object, data)) -class DeviceNotFound(Exception): - """Device was not found.""" - - class Devices(ObjectSet, metaclass=DevicesType): """The set of devices stored in MAAS.""" diff --git a/maas/client/viscera/zones.py b/maas/client/viscera/zones.py index efdb6c8..61f07c7 100644 --- a/maas/client/viscera/zones.py +++ b/maas/client/viscera/zones.py @@ -23,10 +23,6 @@ async def read(cls): return cls(map(cls._object, data)) -class ZoneNotFound(Exception): - """Zone was not found.""" - - class Zones(ObjectSet, metaclass=ZonesType): """The set of zones stored in MAAS.""" From 233f376e5f918d57a74ce956a9735d6069573bd4 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 10:39:55 +0000 Subject: [PATCH 036/245] Get MAAS config setting and getting working. --- maas/client/viscera/maas.py | 46 ++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/maas/client/viscera/maas.py b/maas/client/viscera/maas.py index 20ee6ae..488dd2d 100644 --- a/maas/client/viscera/maas.py +++ b/maas/client/viscera/maas.py @@ -19,6 +19,24 @@ from ..utils.typecheck import typed +def _django_boolean(boolean): + """Render a string suitable for use in a Django form. + + Django's `BooleanField` understands "true", "false", "1", "0", "t", and + "f" as valid form values, but the widget `CheckboxInput` that is used by + `BooleanField` by default gets a shot at converting the form input first. + It inexplicably has different rules. See in `value_from_datadict`: + + values = {'true': True, 'false': False} + if isinstance(value, six.string_types): + value = values.get(value.lower(), value) + return bool(value) + + Sigh. + """ + return "true" if boolean else "false" + + class DescriptiveEnum(enum.Enum): """An enum where each member is a `(parameter, description)` tuple.""" @@ -120,7 +138,7 @@ async def get_http_proxy(cls) -> Optional[str]: traffic. MAAS also uses the proxy for downloading boot images. If no URL is provided, the built-in MAAS proxy will be used. """ - data = cls.get_config("http_proxy") + data = await cls.get_config("http_proxy") return None if data is None or data == "" else data @typed @@ -140,7 +158,7 @@ async def get_enable_http_proxy(cls) -> bool: @typed async def set_enable_http_proxy(cls, enabled: bool): """See `get_enable_http_proxy`.""" - await cls.set_config("enable_http_proxy", "1" if enabled else "0") + await cls.set_config("enable_http_proxy", _django_boolean(enabled)) @typed async def get_curtin_verbose(cls) -> bool: @@ -154,7 +172,7 @@ async def get_curtin_verbose(cls) -> bool: @typed async def set_curtin_verbose(cls, verbose: bool): """See `get_curtin_verbose`.""" - await cls.set_config("curtin_verbose", "1" if verbose else "0") + await cls.set_config("curtin_verbose", _django_boolean(verbose)) @typed async def get_kernel_options(cls) -> Optional[str]: @@ -162,7 +180,7 @@ async def get_kernel_options(cls) -> Optional[str]: Boot parameters to pass to the kernel by default. """ - data = cls.get_config("kernel_opts") + data = await cls.get_config("kernel_opts") return None if data is None or data == "" else data @typed @@ -179,7 +197,7 @@ async def get_upstream_dns(cls) -> list: DNS server. This value is used as the value of 'forwarders' in the DNS server config. """ - data = cls.get_config("upstream_dns") + data = await cls.get_config("upstream_dns") return [] if data is None else re.split("[,\s]+", data) @typed @@ -205,7 +223,7 @@ async def get_dnssec_validation(cls) -> DNSSEC: 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. """ - data = cls.get_config("dnssec_validation") + data = await cls.get_config("dnssec_validation") return cls.DNSSEC.lookup(data) @typed @@ -220,7 +238,7 @@ async def get_default_dns_ttl(cls) -> int: If no TTL value is specified at a more specific point this is how long DNS responses are valid, in seconds. """ - return int(cls.get_config("default_dns_ttl")) + return int(await cls.get_config("default_dns_ttl")) @typed async def set_default_dns_ttl(cls, ttl: int): @@ -236,7 +254,7 @@ async def get_enable_disk_erasing_on_release(cls) -> bool: async def set_enable_disk_erasing_on_release(cls, erase: bool): """Should nodes' disks be erased prior to releasing.""" await cls.set_config( - "enable_disk_erasing_on_release", "1" if erase else "0") + "enable_disk_erasing_on_release", _django_boolean(erase)) @typed async def get_windows_kms_host(cls) -> Optional[str]: @@ -246,7 +264,7 @@ async def get_windows_kms_host(cls) -> Optional[str]: activation service. (Only needed for Windows deployments using KMS activation.) """ - data = cls.get_config("windows_kms_host") + data = await cls.get_config("windows_kms_host") return None if data is None or data == "" else data @typed @@ -262,7 +280,7 @@ async def get_boot_images_auto_import(cls) -> bool: @typed async def set_boot_images_auto_import(cls, auto: bool): """See `get_boot_images_auto_import`.""" - await cls.set_config("boot_images_auto_import", "1" if auto else "0") + await cls.set_config("boot_images_auto_import", _django_boolean(auto)) @typed async def get_ntp_server(cls) -> str: @@ -290,7 +308,7 @@ async def get_default_storage_layout(cls) -> StorageLayout: Storage layout that is applied to a node when it is deployed. """ - data = cls.get_config("default_storage_layout") + data = await cls.get_config("default_storage_layout") return cls.StorageLayout.lookup(data) @typed @@ -304,7 +322,7 @@ async def get_default_min_hwe_kernel(cls) -> Optional[str]: The minimum kernel version used on new and commissioned nodes. """ - data = cls.get_config("default_min_hwe_kernel") + data = await cls.get_config("default_min_hwe_kernel") return None if data is None or data == "" else data @typed @@ -322,7 +340,7 @@ async def get_enable_third_party_drivers(cls) -> bool: async def set_enable_third_party_drivers(cls, enabled: bool): """See `get_enable_third_party_drivers`.""" await cls.set_config( - "enable_third_party_drivers", "1" if enabled else "0") + "enable_third_party_drivers", _django_boolean(enabled)) async def get_config(cls, name: str): """Get a configuration value from MAAS. @@ -363,7 +381,7 @@ async def _roundtrip(cls): print(error) print(error.content.decode("utf-8", "replace")) else: - value2 = getter() + value2 = await getter() if value2 != value: print( "!!! Round-trip failed:", repr(value), From 5c4f026746e5af76e03ba8cfc7591c59359a5fca Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 10:40:29 +0000 Subject: [PATCH 037/245] Expose remaining viscera objects via client facades. --- maas/client/_client.py | 88 ++++++++++++++++++++++++- maas/client/tests/test__client.py | 104 +++++++++++++++++++++++++++++- 2 files changed, 188 insertions(+), 4 deletions(-) diff --git a/maas/client/_client.py b/maas/client/_client.py index 9964341..b34fde2 100644 --- a/maas/client/_client.py +++ b/maas/client/_client.py @@ -1,5 +1,6 @@ """Client facade.""" +import enum from functools import update_wrapper @@ -87,6 +88,59 @@ def boot_resources(origin): "stop_import": origin.BootResources.stop_import, } + @facade + def boot_source_selections(origin): + return { + "create": origin.BootSourceSelections.create, + "get": origin.BootSourceSelection.read, + "list": origin.BootSourceSelections.read, + } + + @facade + def boot_sources(origin): + return { + "create": origin.BootSources.create, + "get": origin.BootSource.read, + "list": origin.BootSources.read, + } + + @facade + def devices(origin): + return { + "get": origin.Device.read, + "list": origin.Devices.read, + } + + @facade + def events(origin): + namespace = { + "query": origin.Events.query, + } + namespace.update({ + level.name: level + for level in origin.Events.Level + }) + return namespace + + @facade + def files(origin): + return { + "list": origin.Files.read, + } + + @facade + def maas(origin): + attrs = ( + (name, getattr(origin.MAAS, name)) + for name in dir(origin.MAAS) + if not name.startswith("_") + ) + return { + name: attr for name, attr in attrs if + isinstance(attr, enum.EnumMeta) or + name.startswith(("get_", "set_")) + } + @facade def machines(origin): return { @@ -96,8 +150,36 @@ def machines(origin): } @facade - def devices(origin): + def rack_controllers(origin): return { - "get": origin.Device.read, - "list": origin.Devices.read, + "get": origin.RackController.read, + "list": origin.RackControllers.read, + } + + @facade + def tags(origin): + return { + "create": origin.Tags.create, + "list": origin.Tags.read, + } + + @facade + def users(origin): + return { + "create": origin.Users.create, + "list": origin.Users.read, + "whoami": origin.Users.whoami, + } + + @facade + def version(origin): + return { + "get": origin.Version.read, + } + + @facade + def zones(origin): + return { + "get": origin.Zone.read, + "list": origin.Zones.read, } diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test__client.py index 3fd0950..2461aeb 100644 --- a/maas/client/tests/test__client.py +++ b/maas/client/tests/test__client.py @@ -18,7 +18,13 @@ class TestClient(TestCase): - """Tests for the simplified client.""" + """Tests for the simplified client. + + Right now these are fairly trivial tests, not testing in depth. Work is in + progress to create a unit test framework that will allow testing against + fake MAAS servers that match the "shape" of real MAAS servers. At the + point that lands these tests should be revised. + """ def setUp(self): super(TestClient, self).setUp() @@ -26,6 +32,43 @@ def setUp(self): self.origin = viscera.Origin(self.session) self.client = _client.Client(self.origin) + def test__client_maps_account(self): + self.assertThat(self.client, MatchesClient( + account=MatchesFacade( + create_credentials=self.origin.Account.create_credentials, + delete_credentials=self.origin.Account.delete_credentials, + ), + )) + + def test__client_maps_boot_resources(self): + self.assertThat(self.client, MatchesClient( + boot_resources=MatchesFacade( + create=self.origin.BootResources.create, + get=self.origin.BootResource.read, + list=self.origin.BootResources.read, + start_import=self.origin.BootResources.start_import, + stop_import=self.origin.BootResources.stop_import, + ), + )) + + def test__client_maps_boot_source_selections(self): + self.assertThat(self.client, MatchesClient( + boot_source_selections=MatchesFacade( + create=self.origin.BootSourceSelections.create, + get=self.origin.BootSourceSelection.read, + list=self.origin.BootSourceSelections.read, + ), + )) + + def test__client_maps_boot_sources(self): + self.assertThat(self.client, MatchesClient( + boot_sources=MatchesFacade( + create=self.origin.BootSources.create, + get=self.origin.BootSource.read, + list=self.origin.BootSources.read, + ), + )) + def test__client_maps_devices(self): self.assertThat(self.client, MatchesClient( devices=MatchesFacade( @@ -34,6 +77,25 @@ def test__client_maps_devices(self): ), )) + def test__client_maps_events(self): + self.assertThat(self.client, MatchesClient( + events=MatchesFacade( + query=self.origin.Events.query, + DEBUG=self.origin.Events.Level.DEBUG, + INFO=self.origin.Events.Level.INFO, + WARNING=self.origin.Events.Level.WARNING, + ERROR=self.origin.Events.Level.ERROR, + CRITICAL=self.origin.Events.Level.CRITICAL, + ), + )) + + def test__client_maps_files(self): + self.assertThat(self.client, MatchesClient( + files=MatchesFacade( + list=self.origin.Files.read, + ), + )) + def test__client_maps_machines(self): self.assertThat(self.client, MatchesClient( machines=MatchesFacade( @@ -43,6 +105,46 @@ def test__client_maps_machines(self): ), )) + def test__client_maps_rack_controllers(self): + self.assertThat(self.client, MatchesClient( + rack_controllers=MatchesFacade( + get=self.origin.RackController.read, + list=self.origin.RackControllers.read, + ), + )) + + def test__client_maps_tags(self): + self.assertThat(self.client, MatchesClient( + tags=MatchesFacade( + create=self.origin.Tags.create, + list=self.origin.Tags.read, + ), + )) + + def test__client_maps_users(self): + self.assertThat(self.client, MatchesClient( + users=MatchesFacade( + create=self.origin.Users.create, + list=self.origin.Users.read, + whoami=self.origin.Users.whoami, + ), + )) + + def test__client_maps_version(self): + self.assertThat(self.client, MatchesClient( + version=MatchesFacade( + get=self.origin.Version.read, + ), + )) + + def test__client_maps_zones(self): + self.assertThat(self.client, MatchesClient( + zones=MatchesFacade( + get=self.origin.Zone.read, + list=self.origin.Zones.read, + ), + )) + def MatchesClient(**facades): """Matches a `_client.Client` with the given facades.""" From ede675ce827eaab0c0a101158c9e2005b727546d Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 13:48:41 +0000 Subject: [PATCH 038/245] Move a couple of hand-run tests into the unit test suite. --- maas/client/viscera/maas.py | 12 ----------- maas/client/viscera/tests/test_maas.py | 30 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 12 deletions(-) create mode 100644 maas/client/viscera/tests/test_maas.py diff --git a/maas/client/viscera/maas.py b/maas/client/viscera/maas.py index 488dd2d..f12b95b 100644 --- a/maas/client/viscera/maas.py +++ b/maas/client/viscera/maas.py @@ -387,18 +387,6 @@ async def _roundtrip(cls): "!!! Round-trip failed:", repr(value), "-->", repr(value2)) - getters_without_setters = set(getters).difference(setters) - if getters_without_setters: - print( - "!!! Getters without setters:", - " ".join(getters_without_setters)) - - setters_without_getters = set(setters).difference(getters) - if setters_without_getters: - print( - "!!! Setters without getters:", - " ".join(setters_without_getters)) - class MAAS(Object, metaclass=MAASType): """The current MAAS.""" diff --git a/maas/client/viscera/tests/test_maas.py b/maas/client/viscera/tests/test_maas.py new file mode 100644 index 0000000..cfbc8dc --- /dev/null +++ b/maas/client/viscera/tests/test_maas.py @@ -0,0 +1,30 @@ +"""Tests for MAAS configuration and suchlike.""" + +from testtools.matchers import HasLength + +from .. import maas +from ...testing import TestCase + + +def find_getters(cls): + return { + name[4:]: getattr(cls, name) for name in dir(cls) + if name.startswith("get_") and name != "get_config" + } + + +def find_setters(cls): + return { + name[4:]: getattr(cls, name) for name in dir(cls) + if name.startswith("set_") and name != "set_config" + } + + +class TestConfiguration(TestCase): + + def test__every_getter_has_a_setter_and_vice_versa(self): + getters, setters = find_getters(maas.MAAS), find_setters(maas.MAAS) + getters_without_setters = set(getters).difference(setters) + self.assertThat(getters_without_setters, HasLength(0)) + setters_without_getters = set(setters).difference(getters) + self.assertThat(setters_without_getters, HasLength(0)) From 7f28fbc859f8454bc22bc7d012c95b6f7892b613 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 14:05:09 +0000 Subject: [PATCH 039/245] Don't expose boot source selections just yet; we will probably nest it under boot sources instead. --- maas/client/_client.py | 8 -------- maas/client/tests/test__client.py | 9 --------- 2 files changed, 17 deletions(-) diff --git a/maas/client/_client.py b/maas/client/_client.py index b34fde2..7e2a871 100644 --- a/maas/client/_client.py +++ b/maas/client/_client.py @@ -88,14 +88,6 @@ def boot_resources(origin): "stop_import": origin.BootResources.stop_import, } - @facade - def boot_source_selections(origin): - return { - "create": origin.BootSourceSelections.create, - "get": origin.BootSourceSelection.read, - "list": origin.BootSourceSelections.read, - } - @facade def boot_sources(origin): return { diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test__client.py index 2461aeb..b5caadc 100644 --- a/maas/client/tests/test__client.py +++ b/maas/client/tests/test__client.py @@ -51,15 +51,6 @@ def test__client_maps_boot_resources(self): ), )) - def test__client_maps_boot_source_selections(self): - self.assertThat(self.client, MatchesClient( - boot_source_selections=MatchesFacade( - create=self.origin.BootSourceSelections.create, - get=self.origin.BootSourceSelection.read, - list=self.origin.BootSourceSelections.read, - ), - )) - def test__client_maps_boot_sources(self): self.assertThat(self.client, MatchesClient( boot_sources=MatchesFacade( From 2db8e6bac8a234ad73e5680d1f3035431b91d3fa Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 14:14:20 +0000 Subject: [PATCH 040/245] Pull in some updated parts of the typecheck module from MAAS. --- maas/client/utils/typecheck.py | 82 +++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 15 deletions(-) diff --git a/maas/client/utils/typecheck.py b/maas/client/utils/typecheck.py index 57d1c19..7260cfc 100644 --- a/maas/client/utils/typecheck.py +++ b/maas/client/utils/typecheck.py @@ -10,6 +10,17 @@ import inspect import typing +# Some releases of the `typing` module, even within the same major/minor/patch +# version of Python, have changed their issubclass behaviour, breaking this +# module. Changing a module's public API without bumping Python's version is +# not cool. See bug 1650202. +try: + issubclass(str, typing.Optional[str]) +except TypeError: + typing_is_broken = True +else: + typing_is_broken = False + class AnnotationError(TypeError): """An annotation has not been understood.""" @@ -20,9 +31,10 @@ class ArgumentTypeError(TypeError): def __init__(self, func, name, value, expected): super(ArgumentTypeError, self).__init__( - "In %s, for argument '%s', %r is not of type %s; it is of type %s." - % (name_of(func), name, value, name_of(expected), - name_of(type(value)))) + "In %s, for argument '%s', %r is not of type %s; " + "it is of type %s." % ( + name_of(func), name, value, describe_typesig(expected), + name_of(type(value)))) class ReturnTypeError(TypeError): @@ -30,11 +42,32 @@ class ReturnTypeError(TypeError): def __init__(self, func, value, expected): super(ReturnTypeError, self).__init__( - "In %s, the returned value %r is not of type %s; it is of type %s." - % (name_of(func), value, name_of(expected), name_of(type(value)))) + "In %s, the returned value %r is not of type %s; " + "it is of type %s." % ( + name_of(func), value, describe_typesig(expected), + name_of(type(value)))) def typed(func): + """Decorate `func` and check types on arguments and return values. + + `func` is a callable with type annotations, like:: + + @typed + def do_something(foo: str, bar: int) -> str: + return foo * bar + + It's also possible to use typing information from the built-in `typing` + module:: + + @typed + def do_something(foo: AnyStr, bar: SupportsInt) -> AnyStr: + return foo * int(bar) + + Checking type signatures can be slow, so it's better to import `typed` + from `provisioningserver.utils`; that becomes a no-op in deployed + environments. + """ signature = inspect.signature(func) type_hints = typing.get_type_hints(func) types_in = tuple(get_types_in(type_hints, func)) @@ -91,7 +124,18 @@ def checked(*args, **kwargs): return checked +if typing_is_broken: + def typed(func): # noqa + """Return `func` unchanged. + + This release of Python has a "broken" version of `typing` so no type + checks are attempted. + """ + return func + + def get_types_in(hints, func): + """Yield type annotations for function arguments.""" for name, hint in hints.items(): if name == "return": pass # Not handled here. @@ -106,6 +150,7 @@ def get_types_in(hints, func): def get_type_out(hints, func): + """Return a type annotation for the return value.""" if "return" in hints: hint = hints["return"] if hint is None: @@ -121,6 +166,11 @@ def get_type_out(hints, func): def is_typesig(typesig): + """Is `typesig` a type signature? + + A type signature is a subclass of `type`, or a tuple of type signatures + (i.e. recursively). + """ if isinstance(typesig, tuple): if len(typesig) == 0: return False @@ -130,19 +180,21 @@ def is_typesig(typesig): return isinstance(typesig, type) -def name_of(thing): - try: - module = thing.__module__ - except AttributeError: - return qualname_of(thing) +def describe_typesig(typesig): + """Return a string describing `typesig`. + + See `is_typesig` for the definition of a `typesig`. + """ + if issubclass(typesig, typing.Union): + return describe_typesig(typesig.__union_params__) + elif isinstance(typesig, tuple): + return " or ".join(map(describe_typesig, typesig)) else: - if module == "typing": - return repr(thing) - else: - return qualname_of(thing) + return name_of(typesig) -def qualname_of(thing): +def name_of(thing): + """Return a friendly name for `thing`.""" try: return thing.__qualname__ except AttributeError: From 10a14021dc9deb4db218df11352afc58e7a16b69 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 14:56:23 +0000 Subject: [PATCH 041/245] Get the shell working with profile adding and logging-in. --- maas/client/flesh/profiles.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/maas/client/flesh/profiles.py b/maas/client/flesh/profiles.py index 9375b5d..2c7b56b 100644 --- a/maas/client/flesh/profiles.py +++ b/maas/client/flesh/profiles.py @@ -23,6 +23,7 @@ auth, profiles, ) +from ..utils.async import asynchronous class cmd_login_base(Command): @@ -83,14 +84,15 @@ def __init__(self, parser): ), ) - def __call__(self, options): + @asynchronous + async def __call__(self, options): # Special-case when password is "-", meaning read from stdin. if options.password == "-": options.password = sys.stdin.readline().strip() while True: try: - profile = helpers.login( + profile = await helpers.login( options.url, username=options.username, password=options.password, insecure=options.insecure) except helpers.UsernameWithoutPassword: @@ -133,12 +135,13 @@ def __init__(self, parser): ), ) - def __call__(self, options): + @asynchronous + async def __call__(self, options): # Try and obtain credentials interactively if they're not given, or # read them from stdin if they're specified as "-". credentials = auth.obtain_credentials(options.credentials) # Establish a session with the remote API. - session = bones.SessionAPI.fromURL( + session = await bones.SessionAPI.fromURL( options.url, credentials=credentials, insecure=options.insecure) # Make a new profile and save it as the default. profile = profiles.Profile( From df8c415b3ed782f59b4149398bbf98631d61fba3 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 16:04:09 +0000 Subject: [PATCH 042/245] Integration test for rack controller. --- integrate/test.py | 28 +++++++++++++++- maas/client/viscera/controllers.py | 51 +++++++++--------------------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/integrate/test.py b/integrate/test.py index f230e17..52290c1 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -142,7 +142,6 @@ def test__list_boot_sources(self): # TestBootSourceSelections -# TestControllers # TestDevices @@ -244,6 +243,33 @@ def test__allocate_deploy_and_release(self): 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), + )), + ) + + +# TestRegionControllers # TestTags # TestTesting # TestUsers diff --git a/maas/client/viscera/controllers.py b/maas/client/viscera/controllers.py index a15915a..eefe7d8 100644 --- a/maas/client/viscera/controllers.py +++ b/maas/client/viscera/controllers.py @@ -42,65 +42,44 @@ class RackController(Object, metaclass=RackControllerType): architecture = ObjectField.Checked( "architecture", check_optional(str), check_optional(str)) - boot_disk = ObjectField.Checked( - "boot_disk", check_optional(str), check_optional(str)) cpus = ObjectField.Checked( "cpu_count", check(int), check(int)) - disable_ipv4 = ObjectField.Checked( - "disable_ipv4", check(bool), check(bool)) distro_series = ObjectField.Checked( "distro_series", check(str), check(str)) + + # domain + + fqdn = ObjectField.Checked( + "fqdn", check(str), check(str)) hostname = ObjectField.Checked( "hostname", check(str), check(str)) - hwe_kernel = ObjectField.Checked( - "hwe_kernel", check_optional(str), check_optional(str)) + + # interface_set + ip_addresses = ObjectField.Checked( "ip_addresses", check(List[str]), readonly=True) memory = ObjectField.Checked( "memory", check(int), check(int)) - min_hwe_kernel = ObjectField.Checked( - "min_hwe_kernel", check_optional(str), check_optional(str)) - # blockdevice_set - # interface_set - # macaddress_set - # netboot + # node_type + # node_type_name # osystem - # owner - # physicalblockdevice_set # TODO: Use an enum here. power_state = ObjectField.Checked( "power_state", check(str), readonly=True) # power_type - # pxe_mac - # resource_uri - # routers - # status - # storage - - status = ObjectField.Checked( - "status", check(int), readonly=True) - status_action = ObjectField.Checked( - "substatus_action", check_optional(str), readonly=True) - status_message = ObjectField.Checked( - "substatus_message", check_optional(str), readonly=True) - status_name = ObjectField.Checked( - "substatus_name", check(str), readonly=True) - + # service_set + # status_action # swap_size system_id = ObjectField.Checked( "system_id", check(str), readonly=True) - tags = ObjectField.Checked( - "tag_names", check(List[str]), readonly=True) - - # virtualblockdevice_set zone = zones.ZoneField( "zone", readonly=True) - # def __repr__(self): - # return super(RackController, self).__repr__( - # fields={"system_id", "hostname"}) + def __repr__(self): + return super(RackController, self).__repr__( + fields={"system_id", "fqdn"}) From d5fa025a9ef5a40e12bd4b819e1768e6c5dec0a5 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 16:35:31 +0000 Subject: [PATCH 043/245] Add region controllers. --- integrate/test.py | 27 ++++++- maas/client/_client.py | 7 ++ maas/client/tests/test__client.py | 8 +++ maas/client/viscera/controllers.py | 71 ++++++++++++++++++- maas/client/viscera/tests/test_controllers.py | 43 +++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 maas/client/viscera/tests/test_controllers.py diff --git a/integrate/test.py b/integrate/test.py index 52290c1..1f723ac 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -269,7 +269,32 @@ def test__list_rack_controllers(self): ) -# TestRegionControllers +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 diff --git a/maas/client/_client.py b/maas/client/_client.py index 7e2a871..a5460b8 100644 --- a/maas/client/_client.py +++ b/maas/client/_client.py @@ -148,6 +148,13 @@ def rack_controllers(origin): "list": origin.RackControllers.read, } + @facade + def region_controllers(origin): + return { + "get": origin.RegionController.read, + "list": origin.RegionControllers.read, + } + @facade def tags(origin): return { diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test__client.py index b5caadc..1868801 100644 --- a/maas/client/tests/test__client.py +++ b/maas/client/tests/test__client.py @@ -104,6 +104,14 @@ def test__client_maps_rack_controllers(self): ), )) + def test__client_maps_region_controllers(self): + self.assertThat(self.client, MatchesClient( + region_controllers=MatchesFacade( + get=self.origin.RegionController.read, + list=self.origin.RegionControllers.read, + ), + )) + def test__client_maps_tags(self): self.assertThat(self.client, MatchesClient( tags=MatchesFacade( diff --git a/maas/client/viscera/controllers.py b/maas/client/viscera/controllers.py index eefe7d8..1f61cae 100644 --- a/maas/client/viscera/controllers.py +++ b/maas/client/viscera/controllers.py @@ -3,6 +3,8 @@ __all__ = [ "RackController", "RackControllers", + "RegionController", + "RegionControllers", ] from typing import List @@ -82,4 +84,71 @@ class RackController(Object, metaclass=RackControllerType): def __repr__(self): return super(RackController, self).__repr__( - fields={"system_id", "fqdn"}) + fields={"system_id", "hostname"}) + + +class RegionControllersType(ObjectType): + """Metaclass for `RegionControllers`.""" + + async def read(cls): + data = await cls._handler.read() + return cls(map(cls._object, data)) + + +class RegionControllers(ObjectSet, metaclass=RegionControllersType): + """The set of region-controllers stored in MAAS.""" + + +class RegionControllerType(ObjectType): + + async def read(cls, system_id): + data = await cls._handler.read(system_id=system_id) + return cls(data) + + +class RegionController(Object, metaclass=RegionControllerType): + """A region-controller stored in MAAS.""" + + architecture = ObjectField.Checked( + "architecture", check_optional(str), check_optional(str)) + cpus = ObjectField.Checked( + "cpu_count", check(int), check(int)) + distro_series = ObjectField.Checked( + "distro_series", check(str), check(str)) + + # domain + + fqdn = ObjectField.Checked( + "fqdn", check(str), check(str)) + hostname = ObjectField.Checked( + "hostname", check(str), check(str)) + + # interface_set + + ip_addresses = ObjectField.Checked( + "ip_addresses", check(List[str]), readonly=True) + memory = ObjectField.Checked( + "memory", check(int), check(int)) + + # node_type + # node_type_name + # osystem + + # TODO: Use an enum here. + power_state = ObjectField.Checked( + "power_state", check(str), readonly=True) + + # power_type + # service_set + # status_action + # swap_size + + system_id = ObjectField.Checked( + "system_id", check(str), readonly=True) + + zone = zones.ZoneField( + "zone", readonly=True) + + def __repr__(self): + return super(RegionController, self).__repr__( + fields={"system_id", "hostname"}) diff --git a/maas/client/viscera/tests/test_controllers.py b/maas/client/viscera/tests/test_controllers.py new file mode 100644 index 0000000..d6b62f9 --- /dev/null +++ b/maas/client/viscera/tests/test_controllers.py @@ -0,0 +1,43 @@ +"""Test for `maas.client.viscera.controllers`.""" + +from testtools.matchers import Equals + +from .. import controllers +from ...testing import ( + make_name_without_spaces, + TestCase, +) +from ..testing import bind + + +def make_origin(): + # Create a new origin with RackController, RegionControllers, + # RackController, and RegionController. + return bind( + controllers.RackControllers, controllers.RackController, + controllers.RegionControllers, controllers.RegionController, + ) + + +class TestRackController(TestCase): + + def test__string_representation_includes_only_system_id_and_hostname(self): + rack_controller = controllers.RackController({ + "system_id": make_name_without_spaces("system-id"), + "hostname": make_name_without_spaces("hostname"), + }) + self.assertThat(repr(rack_controller), Equals( + "" + % rack_controller._data)) + + +class TestRegionController(TestCase): + + def test__string_representation_includes_only_system_id_and_hostname(self): + rack_controller = controllers.RegionController({ + "system_id": make_name_without_spaces("system-id"), + "hostname": make_name_without_spaces("hostname"), + }) + self.assertThat(repr(rack_controller), Equals( + "" + % rack_controller._data)) From 320b97db003afc3908e5e8265331eb6d1e6cd1fb Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 16:36:48 +0000 Subject: [PATCH 044/245] Remove a file that was previously renamed but which Git appears to have resurrected. --- maas/client/tests/test_client.py | 58 -------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 maas/client/tests/test_client.py diff --git a/maas/client/tests/test_client.py b/maas/client/tests/test_client.py deleted file mode 100644 index d37e3b2..0000000 --- a/maas/client/tests/test_client.py +++ /dev/null @@ -1,58 +0,0 @@ -"""Tests for `maas.client`.""" - -__all__ = [] - -from inspect import signature -from unittest.mock import sentinel - -from testtools.matchers import ( - Equals, - Is, - IsInstance, - Not, -) - -from .. import _client -from ... import client -from ..testing import TestCase -from ..viscera import Origin - - -class TestFunctions(TestCase): - """Tests for module functions.""" - - def test__connect_matches_Origin_connect(self): - stub, real = client.connect, Origin.connect - self.assertSignaturesMatch(stub, real) - - def test__connect_calls_through_to_Origin(self): - connect = self.patch(Origin, "connect") - connect.return_value = sentinel.profile, sentinel.origin - client_object = client.connect( - sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) - connect.assert_called_once_with( - sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) - self.assertThat(client_object, IsInstance(_client.Client)) - self.assertThat(client_object._origin, Is(sentinel.origin)) - - def test__login_matches_Origin_login(self): - stub, real = client.login, Origin.login - self.assertSignaturesMatch(stub, real) - - def test__login_calls_through_to_Origin(self): - login = self.patch(Origin, "login") - login.return_value = sentinel.profile, sentinel.origin - client_object = client.login( - sentinel.url, username=sentinel.username, - password=sentinel.password, insecure=sentinel.insecure) - login.assert_called_once_with( - sentinel.url, username=sentinel.username, - password=sentinel.password, insecure=sentinel.insecure) - self.assertThat(client_object, IsInstance(_client.Client)) - self.assertThat(client_object._origin, Is(sentinel.origin)) - - def assertSignaturesMatch(self, stub, real): - self.assertThat(stub, Not(Is(real))) - sig_stub = signature(client.connect) - sig_real = signature(Origin.connect) - self.assertThat(sig_stub, Equals(sig_real)) From 4b57a351e3ee2527d08ba187eb7bd21ed7e6e734 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 17:01:57 +0000 Subject: [PATCH 045/245] Rename maas.client._client to m.c.facade. --- integrate/test.py | 2 +- maas/client/__init__.py | 11 ++++++++--- maas/client/{_client.py => facade.py} | 0 maas/client/tests/test.py | 6 +++--- .../client/tests/{test__client.py => test_facade.py} | 12 ++++++------ 5 files changed, 18 insertions(+), 13 deletions(-) rename maas/client/{_client.py => facade.py} (100%) rename maas/client/tests/{test__client.py => test_facade.py} (95%) diff --git a/integrate/test.py b/integrate/test.py index 1f723ac..13d57b4 100644 --- a/integrate/test.py +++ b/integrate/test.py @@ -196,7 +196,7 @@ def test__list_machines(self): )), ) - def test__allocate_deploy_and_release(self): + def XXXtest__allocate_deploy_and_release(self): machines_ready = [ machine for machine in self.origin.Machines.read() if machine.status_name == "Ready" diff --git a/maas/client/__init__.py b/maas/client/__init__.py index 55532e1..a348fa9 100644 --- a/maas/client/__init__.py +++ b/maas/client/__init__.py @@ -1,6 +1,9 @@ """Basic entry points.""" -from . import _client +__all__ = [ + "connect", + "login", +] def connect(url, *, apikey=None, insecure=False): @@ -13,10 +16,11 @@ 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) + return Client(origin) def login(url, *, username=None, password=None, insecure=False): @@ -29,7 +33,8 @@ 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) + return Client(origin) diff --git a/maas/client/_client.py b/maas/client/facade.py similarity index 100% rename from maas/client/_client.py rename to maas/client/facade.py diff --git a/maas/client/tests/test.py b/maas/client/tests/test.py index d37e3b2..cc21197 100644 --- a/maas/client/tests/test.py +++ b/maas/client/tests/test.py @@ -12,7 +12,7 @@ Not, ) -from .. import _client +from .. import facade from ... import client from ..testing import TestCase from ..viscera import Origin @@ -32,7 +32,7 @@ def test__connect_calls_through_to_Origin(self): sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) connect.assert_called_once_with( sentinel.url, apikey=sentinel.apikey, insecure=sentinel.insecure) - self.assertThat(client_object, IsInstance(_client.Client)) + self.assertThat(client_object, IsInstance(facade.Client)) self.assertThat(client_object._origin, Is(sentinel.origin)) def test__login_matches_Origin_login(self): @@ -48,7 +48,7 @@ def test__login_calls_through_to_Origin(self): login.assert_called_once_with( sentinel.url, username=sentinel.username, password=sentinel.password, insecure=sentinel.insecure) - self.assertThat(client_object, IsInstance(_client.Client)) + self.assertThat(client_object, IsInstance(facade.Client)) self.assertThat(client_object._origin, Is(sentinel.origin)) def assertSignaturesMatch(self, stub, real): diff --git a/maas/client/tests/test__client.py b/maas/client/tests/test_facade.py similarity index 95% rename from maas/client/tests/test__client.py rename to maas/client/tests/test_facade.py index 1868801..ebd5b44 100644 --- a/maas/client/tests/test__client.py +++ b/maas/client/tests/test_facade.py @@ -11,7 +11,7 @@ ) from .. import ( - _client, + facade, viscera, ) from ..testing import TestCase @@ -30,7 +30,7 @@ def setUp(self): super(TestClient, self).setUp() self.session = Mock(name="session", handlers={}) self.origin = viscera.Origin(self.session) - self.client = _client.Client(self.origin) + self.client = facade.Client(self.origin) def test__client_maps_account(self): self.assertThat(self.client, MatchesClient( @@ -146,18 +146,18 @@ def test__client_maps_zones(self): def MatchesClient(**facades): - """Matches a `_client.Client` with the given facades.""" + """Matches a `facade.Client` with the given facades.""" return MatchesAll( - IsInstance(_client.Client), + IsInstance(facade.Client), MatchesStructure(**facades), first_only=True, ) def MatchesFacade(**methods): - """Matches a `_client.Facade` with the given methods.""" + """Matches a `facade.Facade` with the given methods.""" return MatchesAll( - IsInstance(_client.Facade), + IsInstance(facade.Facade), MatchesStructure.byEquality(**methods), first_only=True, ) From e3e737f36db8ed6ff9c5b747d796688346aa4972 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Mon, 6 Mar 2017 17:27:34 +0000 Subject: [PATCH 046/245] Remove __all__ from tests. --- maas/client/bones/tests/test.py | 2 -- maas/client/flesh/tests/test_profiles.py | 2 -- maas/client/flesh/tests/test_shell.py | 2 -- maas/client/tests/test.py | 2 -- maas/client/tests/test_facade.py | 2 -- maas/client/utils/tests/test.py | 2 -- maas/client/utils/tests/test_async.py | 2 -- maas/client/utils/tests/test_auth.py | 2 -- maas/client/utils/tests/test_creds.py | 2 -- maas/client/utils/tests/test_multipart.py | 2 -- maas/client/utils/tests/test_profiles.py | 2 -- maas/client/viscera/tests/test.py | 2 -- maas/client/viscera/tests/test_account.py | 2 -- maas/client/viscera/tests/test_boot_resources.py | 2 -- maas/client/viscera/tests/test_boot_source_selections.py | 2 -- maas/client/viscera/tests/test_boot_sources.py | 2 -- maas/client/viscera/tests/test_devices.py | 2 -- maas/client/viscera/tests/test_events.py | 2 -- maas/client/viscera/tests/test_files.py | 2 -- maas/client/viscera/tests/test_machines.py | 2 -- maas/client/viscera/tests/test_users.py | 2 -- maas/client/viscera/tests/test_version.py | 2 -- 22 files changed, 44 deletions(-) diff --git a/maas/client/bones/tests/test.py b/maas/client/bones/tests/test.py index 6001dd5..1d1a311 100644 --- a/maas/client/bones/tests/test.py +++ b/maas/client/bones/tests/test.py @@ -1,7 +1,5 @@ """Tests for `maas.client.bones`.""" -__all__ = [] - import json import random from unittest.mock import ( diff --git a/maas/client/flesh/tests/test_profiles.py b/maas/client/flesh/tests/test_profiles.py index 134ca19..e94abe8 100644 --- a/maas/client/flesh/tests/test_profiles.py +++ b/maas/client/flesh/tests/test_profiles.py @@ -1,7 +1,5 @@ """Tests for `maas.client.flesh.profiles`.""" -__all__ = [] - from io import StringIO import sys from textwrap import dedent diff --git a/maas/client/flesh/tests/test_shell.py b/maas/client/flesh/tests/test_shell.py index a080c3f..a9705a7 100644 --- a/maas/client/flesh/tests/test_shell.py +++ b/maas/client/flesh/tests/test_shell.py @@ -1,7 +1,5 @@ """Tests for `maas.client.flesh.shell`.""" -__all__ = [] - import random from testtools.matchers import ( diff --git a/maas/client/tests/test.py b/maas/client/tests/test.py index cc21197..6c14e70 100644 --- a/maas/client/tests/test.py +++ b/maas/client/tests/test.py @@ -1,7 +1,5 @@ """Tests for `maas.client`.""" -__all__ = [] - from inspect import signature from unittest.mock import sentinel diff --git a/maas/client/tests/test_facade.py b/maas/client/tests/test_facade.py index ebd5b44..d822942 100644 --- a/maas/client/tests/test_facade.py +++ b/maas/client/tests/test_facade.py @@ -1,7 +1,5 @@ """Tests for `maas.client._client`.""" -__all__ = [] - from unittest.mock import Mock from testtools.matchers import ( diff --git a/maas/client/utils/tests/test.py b/maas/client/utils/tests/test.py index 81c95f4..e9a7cb3 100644 --- a/maas/client/utils/tests/test.py +++ b/maas/client/utils/tests/test.py @@ -1,7 +1,5 @@ """Tests for `maas.client.utils`.""" -__all__ = [] - import base64 from functools import partial from itertools import cycle diff --git a/maas/client/utils/tests/test_async.py b/maas/client/utils/tests/test_async.py index b94b811..284c867 100644 --- a/maas/client/utils/tests/test_async.py +++ b/maas/client/utils/tests/test_async.py @@ -14,8 +14,6 @@ """Tests for asynchronous helpers.""" -__all__ = [] - import asyncio from inspect import isawaitable diff --git a/maas/client/utils/tests/test_auth.py b/maas/client/utils/tests/test_auth.py index 779ec5f..516bbdc 100644 --- a/maas/client/utils/tests/test_auth.py +++ b/maas/client/utils/tests/test_auth.py @@ -1,7 +1,5 @@ """Tests for `maas.client.utils.auth`.""" -__all__ = [] - import sys from unittest.mock import ( ANY, diff --git a/maas/client/utils/tests/test_creds.py b/maas/client/utils/tests/test_creds.py index ab88c46..b642b66 100644 --- a/maas/client/utils/tests/test_creds.py +++ b/maas/client/utils/tests/test_creds.py @@ -1,7 +1,5 @@ """Tests for handling of MAAS API credentials.""" -__all__ = [] - from testtools.matchers import IsInstance from ...testing import TestCase diff --git a/maas/client/utils/tests/test_multipart.py b/maas/client/utils/tests/test_multipart.py index d611532..a47edd8 100644 --- a/maas/client/utils/tests/test_multipart.py +++ b/maas/client/utils/tests/test_multipart.py @@ -1,7 +1,5 @@ """Test multipart MIME helpers.""" -__all__ = [] - from io import BytesIO from os import urandom diff --git a/maas/client/utils/tests/test_profiles.py b/maas/client/utils/tests/test_profiles.py index aca21c1..48852f0 100644 --- a/maas/client/utils/tests/test_profiles.py +++ b/maas/client/utils/tests/test_profiles.py @@ -1,7 +1,5 @@ """Tests for `maas.client.utils.profiles`.""" -__all__ = [] - import contextlib from pathlib import Path import sqlite3 diff --git a/maas/client/viscera/tests/test.py b/maas/client/viscera/tests/test.py index b6fc1df..00e957f 100644 --- a/maas/client/viscera/tests/test.py +++ b/maas/client/viscera/tests/test.py @@ -1,7 +1,5 @@ """Tests for `maas.client.viscera`.""" -__all__ = [] - from random import randrange from unittest.mock import sentinel diff --git a/maas/client/viscera/tests/test_account.py b/maas/client/viscera/tests/test_account.py index a6dbf45..acc195c 100644 --- a/maas/client/viscera/tests/test_account.py +++ b/maas/client/viscera/tests/test_account.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.account`.""" -__all__ = [] - from testtools.matchers import ( Equals, IsInstance, diff --git a/maas/client/viscera/tests/test_boot_resources.py b/maas/client/viscera/tests/test_boot_resources.py index f730204..0acaa97 100644 --- a/maas/client/viscera/tests/test_boot_resources.py +++ b/maas/client/viscera/tests/test_boot_resources.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.boot_resources`.""" -__all__ = [] - import hashlib from http import HTTPStatus import io diff --git a/maas/client/viscera/tests/test_boot_source_selections.py b/maas/client/viscera/tests/test_boot_source_selections.py index b030a42..e3e3e8f 100644 --- a/maas/client/viscera/tests/test_boot_source_selections.py +++ b/maas/client/viscera/tests/test_boot_source_selections.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.boot_source_selections`.""" -__all__ = [] - import random from testtools.matchers import ( diff --git a/maas/client/viscera/tests/test_boot_sources.py b/maas/client/viscera/tests/test_boot_sources.py index 56f7bab..3eaa343 100644 --- a/maas/client/viscera/tests/test_boot_sources.py +++ b/maas/client/viscera/tests/test_boot_sources.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.boot_sources`.""" -__all__ = [] - import random from testtools.matchers import ( diff --git a/maas/client/viscera/tests/test_devices.py b/maas/client/viscera/tests/test_devices.py index 32994f3..49d5232 100644 --- a/maas/client/viscera/tests/test_devices.py +++ b/maas/client/viscera/tests/test_devices.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.devices`.""" -__all__ = [] - from testtools.matchers import Equals from .. import devices diff --git a/maas/client/viscera/tests/test_events.py b/maas/client/viscera/tests/test_events.py index 01b5894..cf7a4ec 100644 --- a/maas/client/viscera/tests/test_events.py +++ b/maas/client/viscera/tests/test_events.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.events`.""" -__all__ = [] - from datetime import datetime from itertools import ( chain, diff --git a/maas/client/viscera/tests/test_files.py b/maas/client/viscera/tests/test_files.py index 1777bdb..725ea6d 100644 --- a/maas/client/viscera/tests/test_files.py +++ b/maas/client/viscera/tests/test_files.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.files`.""" -__all__ = [] - from testtools.matchers import ( AllMatch, IsInstance, diff --git a/maas/client/viscera/tests/test_machines.py b/maas/client/viscera/tests/test_machines.py index 655bffa..d7f5d66 100644 --- a/maas/client/viscera/tests/test_machines.py +++ b/maas/client/viscera/tests/test_machines.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.machines`.""" -__all__ = [] - from testtools.matchers import Equals from .. import machines diff --git a/maas/client/viscera/tests/test_users.py b/maas/client/viscera/tests/test_users.py index f3ca6f1..99e1507 100644 --- a/maas/client/viscera/tests/test_users.py +++ b/maas/client/viscera/tests/test_users.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.users`.""" -__all__ = [] - from testtools.matchers import ( Equals, MatchesStructure, diff --git a/maas/client/viscera/tests/test_version.py b/maas/client/viscera/tests/test_version.py index 3c3f20a..cbf2eda 100644 --- a/maas/client/viscera/tests/test_version.py +++ b/maas/client/viscera/tests/test_version.py @@ -1,7 +1,5 @@ """Test for `maas.client.viscera.version`.""" -__all__ = [] - from random import randrange from testtools.matchers import Equals From 29a5b6ba88f5ea22da1c94337d0a76d4a2afc121 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 08:53:16 +0000 Subject: [PATCH 047/245] Remove typecheck and other uses of typing with issubclass and/or isinstance. --- maas/client/bones/helpers.py | 2 - maas/client/utils/profiles.py | 6 - maas/client/utils/typecheck.py | 201 -------------------------- maas/client/utils/types.py | 18 +-- maas/client/viscera/account.py | 3 - maas/client/viscera/boot_resources.py | 4 - maas/client/viscera/events.py | 2 - maas/client/viscera/maas.py | 41 ------ 8 files changed, 1 insertion(+), 276 deletions(-) delete mode 100644 maas/client/utils/typecheck.py diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index 75dc1bb..1b1d662 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -26,14 +26,12 @@ from ..utils.auth import obtain_token from ..utils.creds import Credentials from ..utils.profiles import Profile -from ..utils.typecheck import typed class RemoteError(Exception): """Miscellaneous error related to a remote system.""" -@typed async def fetch_api_description( url: str, credentials: Optional[Credentials]=None, insecure: bool=False): diff --git a/maas/client/utils/profiles.py b/maas/client/utils/profiles.py index 68e00ef..0d21f0e 100644 --- a/maas/client/utils/profiles.py +++ b/maas/client/utils/profiles.py @@ -20,7 +20,6 @@ from . import api_url from .creds import Credentials -from .typecheck import typed from .types import JSONObject @@ -29,7 +28,6 @@ class Profile(tuple): __slots__ = () - @typed def __new__( cls, name: str, url: str, *, credentials: Union[Credentials, Sequence, str, None], @@ -175,7 +173,6 @@ def __iter__(self): results = self.database.execute("SELECT name FROM profiles").fetchall() return (name for (name,) in results) - @typed def load(self, name: str) -> Profile: found = self.database.execute( "SELECT data FROM profiles" @@ -187,7 +184,6 @@ def load(self, name: str) -> Profile: state["name"] = name # Belt-n-braces. return Profile(**state) - @typed def save(self, profile: Profile): state = profile.dump() data = json.dumps(state) @@ -205,7 +201,6 @@ def save(self, profile: Profile): "UPDATE profiles SET data = ? WHERE name = ?", (data, profile.name)) - @typed def delete(self, name: str): self.database.execute( "DELETE FROM profiles WHERE name = ?", (name,)) @@ -224,7 +219,6 @@ def default(self) -> Optional[Profile]: return Profile(**state) @default.setter - @typed def default(self, profile: Profile): with self.database: self.save(profile) diff --git a/maas/client/utils/typecheck.py b/maas/client/utils/typecheck.py deleted file mode 100644 index 7260cfc..0000000 --- a/maas/client/utils/typecheck.py +++ /dev/null @@ -1,201 +0,0 @@ -"""Check Python 3 type hints.""" - -__all__ = [ - "ArgumentTypeError", - "ReturnTypeError", - "typed", -] - -from functools import wraps -import inspect -import typing - -# Some releases of the `typing` module, even within the same major/minor/patch -# version of Python, have changed their issubclass behaviour, breaking this -# module. Changing a module's public API without bumping Python's version is -# not cool. See bug 1650202. -try: - issubclass(str, typing.Optional[str]) -except TypeError: - typing_is_broken = True -else: - typing_is_broken = False - - -class AnnotationError(TypeError): - """An annotation has not been understood.""" - - -class ArgumentTypeError(TypeError): - """An argument was of the wrong type.""" - - def __init__(self, func, name, value, expected): - super(ArgumentTypeError, self).__init__( - "In %s, for argument '%s', %r is not of type %s; " - "it is of type %s." % ( - name_of(func), name, value, describe_typesig(expected), - name_of(type(value)))) - - -class ReturnTypeError(TypeError): - """The return value was of the wrong type.""" - - def __init__(self, func, value, expected): - super(ReturnTypeError, self).__init__( - "In %s, the returned value %r is not of type %s; " - "it is of type %s." % ( - name_of(func), value, describe_typesig(expected), - name_of(type(value)))) - - -def typed(func): - """Decorate `func` and check types on arguments and return values. - - `func` is a callable with type annotations, like:: - - @typed - def do_something(foo: str, bar: int) -> str: - return foo * bar - - It's also possible to use typing information from the built-in `typing` - module:: - - @typed - def do_something(foo: AnyStr, bar: SupportsInt) -> AnyStr: - return foo * int(bar) - - Checking type signatures can be slow, so it's better to import `typed` - from `provisioningserver.utils`; that becomes a no-op in deployed - environments. - """ - signature = inspect.signature(func) - type_hints = typing.get_type_hints(func) - types_in = tuple(get_types_in(type_hints, func)) - type_out = get_type_out(type_hints, func) - - def check_in(args, kwargs): - bound = signature.bind(*args, **kwargs) - bound.apply_defaults() - # Check incoming arguments. - for name, type_in in types_in: - # An empty *args, for example, will not appear in the bound - # arguments list, so we much check for that. - if name in bound.arguments: - value = bound.arguments[name] - if not issubclass(type(value), type_in): - raise ArgumentTypeError(func, name, value, type_in) - - def check_out(result): - if not issubclass(type(result), type_out): - raise ReturnTypeError(func, result, type_out) - - if inspect.iscoroutinefunction(func): - if type_out is None: - @wraps(func) - async def checked(*args, **kwargs): - check_in(args, kwargs) - # No annotation on return value. - return await func(*args, **kwargs) - - else: - @wraps(func) - async def checked(*args, **kwargs): - check_in(args, kwargs) - result = await func(*args, **kwargs) - check_out(result) - return result - - else: - if type_out is None: - @wraps(func) - def checked(*args, **kwargs): - check_in(args, kwargs) - # No annotation on return value. - return func(*args, **kwargs) - - else: - @wraps(func) - def checked(*args, **kwargs): - check_in(args, kwargs) - result = func(*args, **kwargs) - check_out(result) - return result - - return checked - - -if typing_is_broken: - def typed(func): # noqa - """Return `func` unchanged. - - This release of Python has a "broken" version of `typing` so no type - checks are attempted. - """ - return func - - -def get_types_in(hints, func): - """Yield type annotations for function arguments.""" - for name, hint in hints.items(): - if name == "return": - pass # Not handled here. - elif hint is None: - yield name, type(None) # Special case for None. - elif is_typesig(hint): - yield name, hint - else: - raise AnnotationError( - "In %s, annotation %r for argument '%s' is " - "not understood." % (name_of(func), hint, name)) - - -def get_type_out(hints, func): - """Return a type annotation for the return value.""" - if "return" in hints: - hint = hints["return"] - if hint is None: - return type(None) # Special case for None. - elif is_typesig(hint): - return hint - else: - raise AnnotationError( - "In %s, annotation %r for return value is " - "not understood." % (name_of(func), hint)) - else: - return None - - -def is_typesig(typesig): - """Is `typesig` a type signature? - - A type signature is a subclass of `type`, or a tuple of type signatures - (i.e. recursively). - """ - if isinstance(typesig, tuple): - if len(typesig) == 0: - return False - else: - return all(map(is_typesig, typesig)) - else: - return isinstance(typesig, type) - - -def describe_typesig(typesig): - """Return a string describing `typesig`. - - See `is_typesig` for the definition of a `typesig`. - """ - if issubclass(typesig, typing.Union): - return describe_typesig(typesig.__union_params__) - elif isinstance(typesig, tuple): - return " or ".join(map(describe_typesig, typesig)) - else: - return name_of(typesig) - - -def name_of(thing): - """Return a friendly name for `thing`.""" - try: - return thing.__qualname__ - except AttributeError: - return repr(thing) diff --git a/maas/client/utils/types.py b/maas/client/utils/types.py index ee41b64..c3b3d95 100644 --- a/maas/client/utils/types.py +++ b/maas/client/utils/types.py @@ -1,9 +1,4 @@ -"""Miscellaneous types. - -Bear in mind that `typecheck` cannot yet check generic types, so using types -like `JSONObject` is currently only partly useful. However, it's still worth -adding such annotations because they also serve a documentary purpose. -""" +"""Miscellaneous types.""" __all__ = [ "JSONArray", @@ -24,14 +19,3 @@ JSONValue = Union[str, int, float, bool, None, "JSONArray", "JSONObject"] JSONArray = Sequence[JSONValue] JSONObject = Dict[str, JSONValue] - -# These are belt-n-braces, but they also seem to help resolve -# forward-references reliably. Without them, things break. -assert issubclass(str, JSONValue) -assert issubclass(int, JSONValue) -assert issubclass(float, JSONValue) -assert issubclass(bool, JSONValue) -assert issubclass(type(None), JSONValue) -assert issubclass(list, JSONValue) -assert issubclass(tuple, JSONValue) -assert issubclass(dict, JSONValue) diff --git a/maas/client/viscera/account.py b/maas/client/viscera/account.py index f739803..32410dc 100644 --- a/maas/client/viscera/account.py +++ b/maas/client/viscera/account.py @@ -9,20 +9,17 @@ ObjectType, ) from ..utils.creds import Credentials -from ..utils.typecheck import typed class AccountType(ObjectType): """Metaclass for `Account`.""" - @typed async def create_credentials(cls) -> Credentials: data = await cls._handler.create_authorisation_token() return Credentials( consumer_key=data["consumer_key"], token_key=data["token_key"], token_secret=data["token_secret"]) - @typed async def delete_credentials(cls, credentials: Credentials) -> None: await cls._handler.delete_authorisation_token( token_key=credentials.token_key) diff --git a/maas/client/viscera/boot_resources.py b/maas/client/viscera/boot_resources.py index cf9b222..aedf884 100644 --- a/maas/client/viscera/boot_resources.py +++ b/maas/client/viscera/boot_resources.py @@ -23,7 +23,6 @@ ) from .. import utils from ..bones import CallError -from ..utils.typecheck import typed def calc_size_and_sha265(content: io.IOBase, chunk_size: int): @@ -106,7 +105,6 @@ async def stop_import(cls): """Stop the import of `BootResource`'s.""" return cls._handler.stop_import() - @typed async def create( cls, name: str, architecture: str, content: io.IOBase, *, title: str="", @@ -173,7 +171,6 @@ async def create( rfile, content, chunk_size, progress_callback) return cls._object.read(resource.id) - @typed async def _upload_chunks( cls, rfile: BootResourceFile, content: io.IOBase, chunk_size: int, progress_callback=None): @@ -199,7 +196,6 @@ async def _upload_chunks( if length != chunk_size: break - @typed async def _put_chunk( cls, session: aiohttp.ClientSession, upload_uri: str, buf: bytes): diff --git a/maas/client/viscera/events.py b/maas/client/viscera/events.py index 4c42a6d..5869fb7 100644 --- a/maas/client/viscera/events.py +++ b/maas/client/viscera/events.py @@ -26,7 +26,6 @@ ObjectType, ) from ..utils.async import is_loop_running -from ..utils.typecheck import typed # # The query API call returns: @@ -86,7 +85,6 @@ class EventsType(ObjectType): Level = Level - @typed async def query( cls, *, hostnames: Iterable[str]=None, diff --git a/maas/client/viscera/maas.py b/maas/client/viscera/maas.py index f12b95b..3aba343 100644 --- a/maas/client/viscera/maas.py +++ b/maas/client/viscera/maas.py @@ -16,7 +16,6 @@ ObjectType, ) from ..bones import CallError -from ..utils.typecheck import typed def _django_boolean(boolean): @@ -62,17 +61,14 @@ def lookup(cls, parameter): class MAASType(ObjectType): """Metaclass for `MAAS`.""" - @typed async def get_name(cls) -> str: """The name of the MAAS instance.""" return await cls.get_config("maas_name") - @typed async def set_name(cls, name: str): """See `get_name`.""" return await cls.set_config("maas_name", name) - @typed async def get_main_archive(cls) -> str: """Main archive URL. @@ -81,12 +77,10 @@ async def get_main_archive(cls) -> str: """ return await cls.get_config("main_archive") - @typed async def set_main_archive(cls, url: str): """See `get_main_archive`.""" await cls.set_config("main_archive", url) - @typed async def get_ports_archive(cls) -> str: """Ports archive. @@ -95,42 +89,34 @@ async def get_ports_archive(cls) -> str: """ return await cls.get_config("ports_archive") - @typed async def set_ports_archive(cls, series: str): """See `get_ports_archive`.""" await cls.set_config("ports_archive", series) - @typed async def get_default_os(cls) -> str: """Default OS used for deployment.""" return await cls.get_config("default_osystem") - @typed async def set_default_os(cls, series: str): """See `get_default_os`.""" await cls.set_config("default_osystem", series) - @typed async def get_default_distro_series(cls) -> str: """Default OS release used for deployment.""" return await cls.get_config("default_distro_series") - @typed async def set_default_distro_series(cls, series: str): """See `get_default_distro_series`.""" await cls.set_config("default_distro_series", series) - @typed async def get_commissioning_distro_series(cls) -> str: """Default Ubuntu release used for commissioning.""" return await cls.get_config("commissioning_distro_series") - @typed async def set_commissioning_distro_series(cls, series: str): """See `get_commissioning_distro_series`.""" await cls.set_config("commissioning_distro_series", series) - @typed async def get_http_proxy(cls) -> Optional[str]: """Proxy for APT and HTTP/HTTPS. @@ -141,12 +127,10 @@ async def get_http_proxy(cls) -> Optional[str]: data = await cls.get_config("http_proxy") return None if data is None or data == "" else data - @typed async def set_http_proxy(cls, url: Optional[str]): """See `get_http_proxy`.""" await cls.set_config("http_proxy", "" if url is None else url) - @typed async def get_enable_http_proxy(cls) -> bool: """Enable the use of an APT and HTTP/HTTPS proxy. @@ -155,12 +139,10 @@ async def get_enable_http_proxy(cls) -> bool: """ return await cls.get_config("enable_http_proxy") - @typed async def set_enable_http_proxy(cls, enabled: bool): """See `get_enable_http_proxy`.""" await cls.set_config("enable_http_proxy", _django_boolean(enabled)) - @typed async def get_curtin_verbose(cls) -> bool: """Should `curtin` log with high verbosity? @@ -169,12 +151,10 @@ async def get_curtin_verbose(cls) -> bool: """ return await cls.get_config("curtin_verbose") - @typed async def set_curtin_verbose(cls, verbose: bool): """See `get_curtin_verbose`.""" await cls.set_config("curtin_verbose", _django_boolean(verbose)) - @typed async def get_kernel_options(cls) -> Optional[str]: """Kernel options. @@ -183,12 +163,10 @@ async def get_kernel_options(cls) -> Optional[str]: data = await cls.get_config("kernel_opts") return None if data is None or data == "" else data - @typed async def set_kernel_options(cls, options: Optional[str]): """See `get_kernel_options`.""" await cls.set_config("kernel_opts", "" if options is None else options) - @typed async def get_upstream_dns(cls) -> list: """Upstream DNS server addresses. @@ -200,7 +178,6 @@ async def get_upstream_dns(cls) -> list: data = await cls.get_config("upstream_dns") return [] if data is None else re.split("[,\s]+", data) - @typed async def set_upstream_dns(cls, addresses: Optional[Sequence[str]]): """See `get_upstream_dns`.""" await cls.set_config("upstream_dns", ( @@ -216,7 +193,6 @@ class DNSSEC(DescriptiveEnum): YES = "yes", "Yes (manually configured root key)" NO = "no", "No (disable DNSSEC)" - @typed async def get_dnssec_validation(cls) -> DNSSEC: """Enable DNSSEC validation of upstream zones. @@ -226,12 +202,10 @@ async def get_dnssec_validation(cls) -> DNSSEC: data = await cls.get_config("dnssec_validation") return cls.DNSSEC.lookup(data) - @typed async def set_dnssec_validation(cls, validation: DNSSEC): """See `get_dnssec_validation`.""" await cls.set_config("dnssec_validation", validation.parameter) - @typed async def get_default_dns_ttl(cls) -> int: """Default Time-To-Live for DNS records. @@ -240,23 +214,19 @@ async def get_default_dns_ttl(cls) -> int: """ return int(await cls.get_config("default_dns_ttl")) - @typed async def set_default_dns_ttl(cls, ttl: int): """See `get_default_dns_ttl`.""" await cls.set_config("default_dns_ttl", str(ttl)) - @typed async def get_enable_disk_erasing_on_release(cls) -> bool: """Should nodes' disks be erased prior to releasing.""" return await cls.get_config("enable_disk_erasing_on_release") - @typed async def set_enable_disk_erasing_on_release(cls, erase: bool): """Should nodes' disks be erased prior to releasing.""" await cls.set_config( "enable_disk_erasing_on_release", _django_boolean(erase)) - @typed async def get_windows_kms_host(cls) -> Optional[str]: """Windows KMS activation host. @@ -267,22 +237,18 @@ async def get_windows_kms_host(cls) -> Optional[str]: data = await cls.get_config("windows_kms_host") return None if data is None or data == "" else data - @typed async def set_windows_kms_host(cls, host: Optional[str]): """See `get_windows_kms_host`.""" await cls.set_config("windows_kms_host", "" if host is None else host) - @typed async def get_boot_images_auto_import(cls) -> bool: """Automatically import/refresh the boot images every 60 minutes.""" return await cls.get_config("boot_images_auto_import") - @typed async def set_boot_images_auto_import(cls, auto: bool): """See `get_boot_images_auto_import`.""" await cls.set_config("boot_images_auto_import", _django_boolean(auto)) - @typed async def get_ntp_server(cls) -> str: """Address of NTP server. @@ -291,7 +257,6 @@ async def get_ntp_server(cls) -> str: """ return await cls.get_config("ntp_server") - @typed async def set_ntp_server(cls, server: str): """See `get_ntp_server`.""" await cls.set_config("ntp_server", server) @@ -302,7 +267,6 @@ class StorageLayout(DescriptiveEnum): LVM = "lvm", "LVM layout" BCACHE = "bcache", "Bcache layout" - @typed async def get_default_storage_layout(cls) -> StorageLayout: """Default storage layout. @@ -311,12 +275,10 @@ async def get_default_storage_layout(cls) -> StorageLayout: data = await cls.get_config("default_storage_layout") return cls.StorageLayout.lookup(data) - @typed async def set_default_storage_layout(cls, series: StorageLayout): """See `get_default_storage_layout`.""" await cls.set_config("default_storage_layout", series.parameter) - @typed async def get_default_min_hwe_kernel(cls) -> Optional[str]: """Default minimum kernel version. @@ -325,18 +287,15 @@ async def get_default_min_hwe_kernel(cls) -> Optional[str]: data = await cls.get_config("default_min_hwe_kernel") return None if data is None or data == "" else data - @typed async def set_default_min_hwe_kernel(cls, version: Optional[str]): """See `get_default_min_hwe_kernel`.""" await cls.set_config( "default_min_hwe_kernel", "" if version is None else version) - @typed async def get_enable_third_party_drivers(cls) -> bool: """Enable the installation of proprietary drivers, e.g. HPVSA.""" return await cls.get_config("enable_third_party_drivers") - @typed async def set_enable_third_party_drivers(cls, enabled: bool): """See `get_enable_third_party_drivers`.""" await cls.set_config( From 2ada0086896a00a6b6dbaa5a8cbb672d4460f345 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 09:48:46 +0000 Subject: [PATCH 048/245] Don't using typing in ObjectField checks. --- maas/client/bones/helpers.py | 4 ++-- maas/client/flesh/__init__.py | 9 +++---- maas/client/utils/creds.py | 4 ++-- maas/client/utils/profiles.py | 12 ++++------ maas/client/viscera/__init__.py | 3 +-- maas/client/viscera/boot_source_selections.py | 14 +++++------ maas/client/viscera/controllers.py | 10 ++++---- maas/client/viscera/devices.py | 10 ++++---- maas/client/viscera/events.py | 17 ++++++------- maas/client/viscera/maas.py | 24 +++++++++---------- maas/client/viscera/machines.py | 23 ++++++++---------- maas/client/viscera/testing.py | 2 +- 12 files changed, 58 insertions(+), 74 deletions(-) diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index 1b1d662..7ebff0b 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -12,7 +12,7 @@ ] from http import HTTPStatus -from typing import Optional +import typing from urllib.parse import ( urljoin, urlparse, @@ -33,7 +33,7 @@ class RemoteError(Exception): async def fetch_api_description( - url: str, credentials: Optional[Credentials]=None, + url: str, credentials: typing.Optional[Credentials]=None, insecure: bool=False): """Fetch the API description from the remote MAAS instance.""" url_describe = urljoin(url, "describe/") diff --git a/maas/client/flesh/__init__.py b/maas/client/flesh/__init__.py index 17ef7a9..f7d727f 100644 --- a/maas/client/flesh/__init__.py +++ b/maas/client/flesh/__init__.py @@ -18,11 +18,7 @@ import argparse from importlib import import_module import sys -from typing import ( - Optional, - Sequence, - Tuple, -) +import typing import argcomplete import colorclass @@ -48,7 +44,8 @@ def colorized(text): return colorclass.Color(text).value_no_colors -def get_profile_names_and_default() -> Tuple[Sequence[str], Optional[Profile]]: +def get_profile_names_and_default() -> ( + typing.Tuple[typing.Sequence[str], typing.Optional[Profile]]): """Return the list of profile names and the default profile object. The list of names is sorted. diff --git a/maas/client/utils/creds.py b/maas/client/utils/creds.py index be8acf5..5a3bda1 100644 --- a/maas/client/utils/creds.py +++ b/maas/client/utils/creds.py @@ -14,7 +14,7 @@ ] from collections import namedtuple -from typing import Optional +import typing CredentialsBase = namedtuple( @@ -27,7 +27,7 @@ class Credentials(CredentialsBase): __slots__ = () @classmethod - def parse(cls, credentials) -> Optional["Credentials"]: + def parse(cls, credentials) -> typing.Optional["Credentials"]: """Parse/interpret some given credentials. These may take the form of: diff --git a/maas/client/utils/profiles.py b/maas/client/utils/profiles.py index 0d21f0e..7de3172 100644 --- a/maas/client/utils/profiles.py +++ b/maas/client/utils/profiles.py @@ -12,11 +12,7 @@ from pathlib import Path import sqlite3 from textwrap import dedent -from typing import ( - Optional, - Sequence, - Union, -) +import typing from . import api_url from .creds import Credentials @@ -30,7 +26,7 @@ class Profile(tuple): def __new__( cls, name: str, url: str, *, - credentials: Union[Credentials, Sequence, str, None], + credentials: typing.Union[Credentials, typing.Sequence, str, None], description: dict, **other: JSONObject): return super(Profile, cls).__new__(cls, ( name, api_url(url), Credentials.parse(credentials), @@ -47,7 +43,7 @@ def url(self) -> str: return self[1] @property - def credentials(self) -> Optional[Credentials]: + def credentials(self) -> typing.Optional[Credentials]: """The credentials for this profile, if set.""" return self[2] @@ -206,7 +202,7 @@ def delete(self, name: str): "DELETE FROM profiles WHERE name = ?", (name,)) @property - def default(self) -> Optional[Profile]: + def default(self) -> typing.Optional[Profile]: """The name of the default profile to use, or `None`.""" found = self.database.execute( "SELECT name, data FROM profiles WHERE selected" diff --git a/maas/client/viscera/__init__.py b/maas/client/viscera/__init__.py index b2e2833..ff49034 100644 --- a/maas/client/viscera/__init__.py +++ b/maas/client/viscera/__init__.py @@ -33,7 +33,6 @@ starmap, ) from types import MethodType -from typing import Optional import pytz @@ -523,7 +522,7 @@ def checker(value): def check_optional(expected): - return check(Optional[expected]) + return check((expected, type(None))) def parse_timestamp(created): diff --git a/maas/client/viscera/boot_source_selections.py b/maas/client/viscera/boot_source_selections.py index 74513f4..d8e3dfd 100644 --- a/maas/client/viscera/boot_source_selections.py +++ b/maas/client/viscera/boot_source_selections.py @@ -5,7 +5,7 @@ "BootSourceSelections", ] -from typing import List +from collections import Sequence from . import ( check, @@ -82,12 +82,12 @@ class BootSourceSelection(Object, metaclass=BootSourceSelectionType): "os", check(str), check(str)) release = ObjectField.Checked( "release", check(str), check(str)) - arches = ObjectField.Checked( - "arches", check(List[str]), check(List[str])) - subarches = ObjectField.Checked( - "subarches", check(List[str]), check(List[str])) - labels = ObjectField.Checked( - "labels", check(List[str]), check(List[str])) + arches = ObjectField.Checked( # List[str] + "arches", check(Sequence), check(Sequence)) + subarches = ObjectField.Checked( # List[str] + "subarches", check(Sequence), check(Sequence)) + labels = ObjectField.Checked( # List[str] + "labels", check(Sequence), check(Sequence)) def __repr__(self): return super(BootSourceSelection, self).__repr__( diff --git a/maas/client/viscera/controllers.py b/maas/client/viscera/controllers.py index 1f61cae..cfcd403 100644 --- a/maas/client/viscera/controllers.py +++ b/maas/client/viscera/controllers.py @@ -7,7 +7,7 @@ "RegionControllers", ] -from typing import List +from collections import Sequence from . import ( check, @@ -58,8 +58,8 @@ class RackController(Object, metaclass=RackControllerType): # interface_set - ip_addresses = ObjectField.Checked( - "ip_addresses", check(List[str]), readonly=True) + ip_addresses = ObjectField.Checked( # List[str] + "ip_addresses", check(Sequence), readonly=True) memory = ObjectField.Checked( "memory", check(int), check(int)) @@ -125,8 +125,8 @@ class RegionController(Object, metaclass=RegionControllerType): # interface_set - ip_addresses = ObjectField.Checked( - "ip_addresses", check(List[str]), readonly=True) + ip_addresses = ObjectField.Checked( # List[str] + "ip_addresses", check(Sequence), readonly=True) memory = ObjectField.Checked( "memory", check(int), check(int)) diff --git a/maas/client/viscera/devices.py b/maas/client/viscera/devices.py index e5a4f95..7be0dcb 100644 --- a/maas/client/viscera/devices.py +++ b/maas/client/viscera/devices.py @@ -5,7 +5,7 @@ "Devices", ] -from typing import List +from collections import Sequence from . import ( check, @@ -41,16 +41,16 @@ class Device(Object, metaclass=DeviceType): hostname = ObjectField.Checked( "hostname", check(str), check(str)) - ip_addresses = ObjectField.Checked( - "ip_addresses", check(List[str]), readonly=True) + ip_addresses = ObjectField.Checked( # List[str] + "ip_addresses", check(Sequence), readonly=True) # owner # resource_uri system_id = ObjectField.Checked( "system_id", check(str), readonly=True) - tags = ObjectField.Checked( - "tag_names", check(List[str]), readonly=True) + tags = ObjectField.Checked( # List[str] + "tag_names", check(Sequence), readonly=True) zone = zones.ZoneField( "zone", readonly=True) diff --git a/maas/client/viscera/events.py b/maas/client/viscera/events.py index 5869fb7..2eeb37e 100644 --- a/maas/client/viscera/events.py +++ b/maas/client/viscera/events.py @@ -8,10 +8,7 @@ import enum from functools import partial import logging -from typing import ( - Iterable, - Union, -) +import typing from urllib.parse import ( parse_qs, urlparse, @@ -87,13 +84,13 @@ class EventsType(ObjectType): async def query( cls, *, - hostnames: Iterable[str]=None, - domains: Iterable[str]=None, - zones: Iterable[str]=None, - macs: Iterable[str]=None, - system_ids: Iterable[str]=None, + hostnames: typing.Iterable[str]=None, + domains: typing.Iterable[str]=None, + zones: typing.Iterable[str]=None, + macs: typing.Iterable[str]=None, + system_ids: typing.Iterable[str]=None, agent_name: str=None, - level: Union[Level, int, str]=None, + level: typing.Union[Level, int, str]=None, before: int=None, after: int=None, limit: int=None): diff --git a/maas/client/viscera/maas.py b/maas/client/viscera/maas.py index 3aba343..a7943d0 100644 --- a/maas/client/viscera/maas.py +++ b/maas/client/viscera/maas.py @@ -6,10 +6,7 @@ import enum import re -from typing import ( - Optional, - Sequence, -) +import typing from . import ( Object, @@ -117,7 +114,7 @@ async def set_commissioning_distro_series(cls, series: str): """See `get_commissioning_distro_series`.""" await cls.set_config("commissioning_distro_series", series) - async def get_http_proxy(cls) -> Optional[str]: + async def get_http_proxy(cls) -> typing.Optional[str]: """Proxy for APT and HTTP/HTTPS. This will be passed onto provisioned nodes to use as a proxy for APT @@ -127,7 +124,7 @@ async def get_http_proxy(cls) -> Optional[str]: data = await cls.get_config("http_proxy") return None if data is None or data == "" else data - async def set_http_proxy(cls, url: Optional[str]): + async def set_http_proxy(cls, url: typing.Optional[str]): """See `get_http_proxy`.""" await cls.set_config("http_proxy", "" if url is None else url) @@ -155,7 +152,7 @@ async def set_curtin_verbose(cls, verbose: bool): """See `get_curtin_verbose`.""" await cls.set_config("curtin_verbose", _django_boolean(verbose)) - async def get_kernel_options(cls) -> Optional[str]: + async def get_kernel_options(cls) -> typing.Optional[str]: """Kernel options. Boot parameters to pass to the kernel by default. @@ -163,7 +160,7 @@ async def get_kernel_options(cls) -> Optional[str]: data = await cls.get_config("kernel_opts") return None if data is None or data == "" else data - async def set_kernel_options(cls, options: Optional[str]): + async def set_kernel_options(cls, options: typing.Optional[str]): """See `get_kernel_options`.""" await cls.set_config("kernel_opts", "" if options is None else options) @@ -178,7 +175,8 @@ async def get_upstream_dns(cls) -> list: data = await cls.get_config("upstream_dns") return [] if data is None else re.split("[,\s]+", data) - async def set_upstream_dns(cls, addresses: Optional[Sequence[str]]): + async def set_upstream_dns( + cls, addresses: typing.Optional[typing.Sequence[str]]): """See `get_upstream_dns`.""" await cls.set_config("upstream_dns", ( "" if addresses is None else",".join(addresses))) @@ -227,7 +225,7 @@ async def set_enable_disk_erasing_on_release(cls, erase: bool): await cls.set_config( "enable_disk_erasing_on_release", _django_boolean(erase)) - async def get_windows_kms_host(cls) -> Optional[str]: + async def get_windows_kms_host(cls) -> typing.Optional[str]: """Windows KMS activation host. FQDN or IP address of the host that provides the KMS Windows @@ -237,7 +235,7 @@ async def get_windows_kms_host(cls) -> Optional[str]: data = await cls.get_config("windows_kms_host") return None if data is None or data == "" else data - async def set_windows_kms_host(cls, host: Optional[str]): + async def set_windows_kms_host(cls, host: typing.Optional[str]): """See `get_windows_kms_host`.""" await cls.set_config("windows_kms_host", "" if host is None else host) @@ -279,7 +277,7 @@ async def set_default_storage_layout(cls, series: StorageLayout): """See `get_default_storage_layout`.""" await cls.set_config("default_storage_layout", series.parameter) - async def get_default_min_hwe_kernel(cls) -> Optional[str]: + async def get_default_min_hwe_kernel(cls) -> typing.Optional[str]: """Default minimum kernel version. The minimum kernel version used on new and commissioned nodes. @@ -287,7 +285,7 @@ async def get_default_min_hwe_kernel(cls) -> Optional[str]: data = await cls.get_config("default_min_hwe_kernel") return None if data is None or data == "" else data - async def set_default_min_hwe_kernel(cls, version: Optional[str]): + async def set_default_min_hwe_kernel(cls, version: typing.Optional[str]): """See `get_default_min_hwe_kernel`.""" await cls.set_config( "default_min_hwe_kernel", "" if version is None else version) diff --git a/maas/client/viscera/machines.py b/maas/client/viscera/machines.py index 6c37c88..a0ebe21 100644 --- a/maas/client/viscera/machines.py +++ b/maas/client/viscera/machines.py @@ -6,12 +6,9 @@ ] import base64 +from collections import Sequence from http import HTTPStatus -from typing import ( - List, - Sequence, - Union, -) +import typing from . import ( check, @@ -33,8 +30,8 @@ async def read(cls): return cls(map(cls._object, data)) async def allocate( - cls, *, hostname: str=None, architecture: str=None, - cpus: int=None, memory: float=None, tags: Sequence[str]=None): + cls, *, hostname: str=None, architecture: str=None, cpus: int=None, + memory: float=None, tags: typing.Sequence[str]=None): """ :param hostname: The hostname to match. :param architecture: The architecture to match, e.g. "amd64". @@ -103,8 +100,8 @@ class Machine(Object, metaclass=MachineType): "hostname", check(str), check(str)) hwe_kernel = ObjectField.Checked( "hwe_kernel", check_optional(str), check_optional(str)) - ip_addresses = ObjectField.Checked( - "ip_addresses", check(List[str]), readonly=True) + ip_addresses = ObjectField.Checked( # List[str] + "ip_addresses", check(Sequence), readonly=True) memory = ObjectField.Checked( "memory", check(int), check(int)) min_hwe_kernel = ObjectField.Checked( @@ -142,8 +139,8 @@ class Machine(Object, metaclass=MachineType): system_id = ObjectField.Checked( "system_id", check(str), readonly=True) - tags = ObjectField.Checked( - "tag_names", check(List[str]), readonly=True) + tags = ObjectField.Checked( # List[str] + "tag_names", check(Sequence), readonly=True) # virtualblockdevice_set @@ -151,8 +148,8 @@ class Machine(Object, metaclass=MachineType): "zone", readonly=True) async def deploy( - self, user_data: Union[bytes, str]=None, distro_series: str=None, - hwe_kernel: str=None, comment: str=None): + self, user_data: typing.Union[bytes, str]=None, + distro_series: str=None, hwe_kernel: str=None, comment: str=None): """Deploy this machine. :param user_data: User-data to provide to the machine when booting. If diff --git a/maas/client/viscera/testing.py b/maas/client/viscera/testing.py index 80578c4..b787dbf 100644 --- a/maas/client/viscera/testing.py +++ b/maas/client/viscera/testing.py @@ -4,8 +4,8 @@ 'bind', ] +from collections import Mapping from itertools import chain -from typing import Mapping from unittest.mock import Mock from . import OriginBase From da9dfa4ec6e2cd1d6387ebd2326ab6cb36b4b0d7 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 15:06:18 +0000 Subject: [PATCH 049/245] Get node listings working, and add region controllers. --- maas/client/flesh/nodes.py | 40 +++++++++++++++++++++++++------------ maas/client/flesh/tables.py | 29 +++++++++++++++------------ 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/maas/client/flesh/nodes.py b/maas/client/flesh/nodes.py index 25bfd21..7154058 100644 --- a/maas/client/flesh/nodes.py +++ b/maas/client/flesh/nodes.py @@ -4,6 +4,7 @@ "register", ] +import asyncio from itertools import chain from time import sleep @@ -14,6 +15,7 @@ tables, ) from .. import utils +from ..utils.async import asynchronous class cmd_allocate_machine(OriginTableCommand): @@ -119,26 +121,38 @@ def __init__(self, parser): parser.add_argument( "--rack-controllers", action="store_true", default=False, help="Show rack-controllers.") - # parser.add_argument( - # "--region-controllers", action="store_true", default=False, - # help="Show region controllers.") + parser.add_argument( + "--region-controllers", action="store_true", default=False, + help="Show region controllers.") - def execute(self, origin, options, target): - nodes = [] + @asynchronous + async def execute(self, origin, options, target): + nodesets = [] if options.all or options.devices: - nodes.append(origin.Devices) + nodesets.append(origin.Devices) if options.all or options.machines: - nodes.append(origin.Machines) + nodesets.append(origin.Machines) if options.all or options.rack_controllers: - nodes.append(origin.RackControllers) - # if options.all or options.regions: - # nodes.append(origin.Regions) + nodesets.append(origin.RackControllers) + if options.all or options.region_controllers: + nodesets.append(origin.RegionControllers) + + if len(nodesets) == 0: + nodesets.append(origin.Machines) + + # Don't make more than two concurrent requests to MAAS. + semaphore = asyncio.Semaphore(2) + + async def read(nodeset): + async with semaphore: + return await nodeset.read() + + nodesets = await asyncio.gather(*map(read, nodesets)) + nodes = chain.from_iterable(nodesets) - if len(nodes) == 0: - nodes.append(origin.Machines) + nodes = list(nodes) - nodes = chain.from_iterable(nodes) table = tables.NodesTable() print(table.render(target, nodes)) diff --git a/maas/client/flesh/tables.py b/maas/client/flesh/tables.py index 871f317..06c9087 100644 --- a/maas/client/flesh/tables.py +++ b/maas/client/flesh/tables.py @@ -12,7 +12,10 @@ from colorclass import Color -from ..viscera.controllers import RackController +from ..viscera.controllers import ( + RackController, + RegionController, +) from ..viscera.devices import Device from ..viscera.machines import Machine from .tabular import ( @@ -188,20 +191,20 @@ def data_for(cls, node): node.architecture, node.cpus, node.memory, - node.status_name, + "—", # status_name + node.power_state, + ) + elif isinstance(node, RegionController): + return ( + NodeTypeColumn.REGION, + node.hostname, + node.system_id, + node.architecture, + node.cpus, + node.memory, + "—", # status_name node.power_state, ) - # elif isinstance(node, RegionController): - # return ( - # "∷", - # node.hostname, - # node.system_id, - # node.architecture, - # node.cpus, - # node.memory, - # node.status_name, - # node.power_state, - # ) else: raise TypeError( "Cannot extract data from %r (%s)" From 72ed9828b66ad04b832af9062174a6e77e053611 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 15:36:07 +0000 Subject: [PATCH 050/245] Get a few more command-line bits working. --- maas/client/flesh/files.py | 2 +- maas/client/flesh/nodes.py | 6 +++--- maas/client/flesh/tags.py | 2 +- maas/client/flesh/users.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/maas/client/flesh/files.py b/maas/client/flesh/files.py index ca7ba71..ef7d758 100644 --- a/maas/client/flesh/files.py +++ b/maas/client/flesh/files.py @@ -15,7 +15,7 @@ class cmd_list_files(OriginTableCommand): def execute(self, origin, options, target): table = tables.FilesTable() - print(table.render(target, origin.Files)) + print(table.render(target, origin.Files.read())) def register(parser): diff --git a/maas/client/flesh/nodes.py b/maas/client/flesh/nodes.py index 7154058..a53315a 100644 --- a/maas/client/flesh/nodes.py +++ b/maas/client/flesh/nodes.py @@ -58,7 +58,7 @@ def execute(self, origin, options, target): print(table.render(target, [machine])) with utils.Spinner(): - machine = machine.start() + machine = machine.deploy() for elapsed, remaining, wait in utils.retries(options.wait, 1.0): if machine.status_name == "Deploying": sleep(wait) @@ -86,14 +86,14 @@ def __init__(self, parser): "Number of seconds to wait for release to complete.")) def execute(self, origin, options, target): - machine = origin.Node.read(system_id=options.system_id) + machine = origin.Machine.read(system_id=options.system_id) machine = machine.release() with utils.Spinner(): for elapsed, remaining, wait in utils.retries(options.wait, 1.0): if machine.status_name == "Releasing": sleep(wait) - machine = origin.Node.read(system_id=machine.system_id) + machine = origin.Machine.read(system_id=machine.system_id) else: break diff --git a/maas/client/flesh/tags.py b/maas/client/flesh/tags.py index 794c892..0e30250 100644 --- a/maas/client/flesh/tags.py +++ b/maas/client/flesh/tags.py @@ -15,7 +15,7 @@ class cmd_list_tags(OriginTableCommand): def execute(self, origin, options, target): table = tables.TagsTable() - print(table.render(target, origin.Tags)) + print(table.render(target, origin.Tags.read())) def register(parser): diff --git a/maas/client/flesh/users.py b/maas/client/flesh/users.py index 11d567f..1dd3ec9 100644 --- a/maas/client/flesh/users.py +++ b/maas/client/flesh/users.py @@ -15,7 +15,7 @@ class cmd_list_users(OriginTableCommand): def execute(self, origin, options, target): table = tables.UsersTable() - print(table.render(target, origin.Users)) + print(table.render(target, origin.Users.read())) def register(parser): From 5054bcc7ab05e88cf16ff6391add2ef3f2e48895 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 16:20:21 +0000 Subject: [PATCH 051/245] Accept already-parsed URLs in fetch_api_description. --- maas/client/bones/helpers.py | 20 ++++++++++++++++++-- maas/client/bones/tests/test_helpers.py | 24 +++++++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index 7ebff0b..77f5154 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -14,6 +14,8 @@ from http import HTTPStatus import typing from urllib.parse import ( + ParseResult, + SplitResult, urljoin, urlparse, ) @@ -33,10 +35,11 @@ class RemoteError(Exception): async def fetch_api_description( - url: str, credentials: typing.Optional[Credentials]=None, + url: typing.Union[str, ParseResult, SplitResult], + credentials: typing.Optional[Credentials]=None, insecure: bool=False): """Fetch the API description from the remote MAAS instance.""" - url_describe = urljoin(url, "describe/") + 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: @@ -52,6 +55,19 @@ async def fetch_api_description( 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): + return url.geturl() + elif isinstance(url, SplitResult): + return url.geturl() + else: + raise TypeError( + "Could not convert %r to a string URL." % (url,)) + + class ConnectError(Exception): """An error with connecting.""" diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index dd28517..2e193c2 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -1,7 +1,10 @@ """Tests for `maas.client.bones.helpers`.""" import json -from urllib.parse import urlparse +from urllib.parse import ( + urlparse, + urlsplit, +) from testtools.matchers import ( Equals, @@ -49,6 +52,25 @@ def test__raises_RemoteError_when_content_not_json(self): str(error)) +class TestFetchAPIDescriptionURLs(TestCase): + """Tests for URL types accepted by `fetch_api_description`.""" + + scenarios = ( + ("string", dict(prepare=str)), + ("split", dict(prepare=urlsplit)), + ("parsed", dict(prepare=urlparse)), + ) + + def test__accepts_prepared_url(self): + description = {"foo": make_name_without_spaces("bar")} + description_json = json.dumps(description).encode("ascii") + fixture = self.useFixture(testing.DescriptionServer(description_json)) + description_url = self.prepare(fixture.url) # Parse, perhaps. + description_fetched = self.loop.run_until_complete( + helpers.fetch_api_description(description_url)) + self.assertThat(description_fetched, Equals(description)) + + class TestFetchAPIDescription_APIVersions(TestCase): """Tests for `fetch_api_description` with multiple API versions.""" From 2ff37b938c317e890c01167cdc34095139d1fbc6 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Tue, 7 Mar 2017 17:41:09 +0000 Subject: [PATCH 052/245] Reimplement obtain_token using aiohttp, and drop dependency on requests. --- maas/client/bones/helpers.py | 75 ++++++++++++++++++++++++- maas/client/bones/tests/test_helpers.py | 18 +++--- maas/client/utils/auth.py | 71 +---------------------- setup.py | 1 - 4 files changed, 85 insertions(+), 80 deletions(-) diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index 77f5154..ca2f905 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -11,7 +11,9 @@ "UsernameWithoutPassword", ] +from getpass import getuser from http import HTTPStatus +from socket import gethostname import typing from urllib.parse import ( ParseResult, @@ -22,10 +24,10 @@ import aiohttp import aiohttp.errors +import bs4 from ..utils import api_url from ..utils.async import asynchronous -from ..utils.auth import obtain_token from ..utils.creds import Credentials from ..utils.profiles import Profile @@ -181,7 +183,7 @@ async def login(url, *, username=None, password=None, insecure=False): raise UsernameWithoutPassword( "User-name provided without password; specify password.") else: - credentials = obtain_token( + credentials = await _obtain_token( url.geturl(), username, password, insecure=insecure) # Circular import. @@ -192,3 +194,72 @@ async def login(url, *, username=None, password=None, insecure=False): return Profile( name=url.netloc, url=url.geturl(), credentials=credentials, description=description) + + +async def _obtain_token(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. + """ + url_login = urljoin(url, "../../accounts/login/") + url_token = urljoin(url, "account/") + + def check_response(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: + + # Fetch and process the log-in page. + async with session.get(url_login) as response: + check_response(response) + login_doc_content = await response.read() + + login_doc = bs4.BeautifulSoup(login_doc_content, "html.parser") + login_button = login_doc.find('button', text="Login") + login_form = login_button.findParent("form") + + # Log-in to MAAS. + login_data = { + elem["name"]: elem["value"] for elem in login_form("input") + if elem.has_attr("name") and elem.has_attr("value") + } + login_data["username"] = username + login_data["password"] = password + # The following `requester` field is not used (at the time of + # writing) but it ought to be associated with this new token so + # that tokens can be selectively revoked at a later date. + login_data["requester"] = "%s@%s" % (getuser(), gethostname()) + + async with session.post(url_login, data=login_data) as response: + check_response(response) + + # Extract the CSRF cookie. + csrf_cookie = next( + cookie for cookie in session.cookie_jar + if cookie.key == "csrftoken") + + # Request a new API token. + create_data = { + "csrfmiddlewaretoken": csrf_cookie.value, + "op": "create_authorisation_token", + } + create_headers = { + "Accept": "application/json", + } + async with session.post( + url_token, data=create_data, + headers=create_headers) as response: + check_response(response) + token = await response.json() + return Credentials( + token["consumer_key"], + token["token_key"], + token["token_secret"], + ) diff --git a/maas/client/bones/tests/test_helpers.py b/maas/client/bones/tests/test_helpers.py index 2e193c2..835878d 100644 --- a/maas/client/bones/tests/test_helpers.py +++ b/maas/client/bones/tests/test_helpers.py @@ -159,7 +159,9 @@ class TestLogin(TestCase): def setUp(self): super(TestLogin, self).setUp() - self.patch(helpers, "obtain_token").return_value = None + self.patch( + helpers, "_obtain_token", + AsyncCallableMock(return_value=None)) self.patch( helpers, "fetch_api_description", AsyncCallableMock(return_value={})) @@ -168,7 +170,7 @@ def test__anonymous_when_neither_username_nor_password_provided(self): # Log-in without a user-name or a password. profile = helpers.login("http://example.org:5240/MAAS/") # No token was obtained, but the description was fetched. - helpers.obtain_token.assert_not_called() + helpers._obtain_token.assert_not_called() helpers.fetch_api_description.assert_called_once_with( urlparse("http://example.org:5240/MAAS/api/2.0/"), None, False) @@ -178,11 +180,11 @@ def test__anonymous_when_neither_username_nor_password_provided(self): def test__authenticated_when_username_and_password_provided(self): credentials = make_Credentials() - helpers.obtain_token.return_value = credentials + helpers._obtain_token.return_value = credentials # Log-in with a user-name and a password. profile = helpers.login("http://foo:bar@example.org:5240/MAAS/") # A token was obtained, and the description was fetched. - helpers.obtain_token.assert_called_once_with( + helpers._obtain_token.assert_called_once_with( "http://example.org:5240/MAAS/api/2.0/", "foo", "bar", insecure=False) helpers.fetch_api_description.assert_called_once_with( @@ -240,7 +242,7 @@ def test__API_description_is_saved_in_profile(self): def test__API_token_is_fetched_insecurely_if_requested(self): helpers.login("http://foo:bar@example.org:5240/MAAS/", insecure=True) - helpers.obtain_token.assert_called_once_with( + helpers._obtain_token.assert_called_once_with( "http://example.org:5240/MAAS/api/2.0/", "foo", "bar", insecure=True) @@ -252,15 +254,15 @@ def test__API_description_is_fetched_insecurely_if_requested(self): def test__uses_username_from_URL_if_set(self): helpers.login("http://foo@maas.io/", password="bar") - helpers.obtain_token.assert_called_once_with( + helpers._obtain_token.assert_called_once_with( "http://maas.io/api/2.0/", "foo", "bar", insecure=False) def test__uses_username_and_password_from_URL_if_set(self): helpers.login("http://foo:bar@maas.io/") - helpers.obtain_token.assert_called_once_with( + helpers._obtain_token.assert_called_once_with( "http://maas.io/api/2.0/", "foo", "bar", insecure=False) def test__uses_empty_username_and_password_in_URL_if_set(self): helpers.login("http://:@maas.io/") - helpers.obtain_token.assert_called_once_with( + helpers._obtain_token.assert_called_once_with( "http://maas.io/api/2.0/", "", "", insecure=False) diff --git a/maas/client/utils/auth.py b/maas/client/utils/auth.py index 36d07b4..e7dd514 100644 --- a/maas/client/utils/auth.py +++ b/maas/client/utils/auth.py @@ -2,20 +2,11 @@ __all__ = [ "obtain_credentials", - "obtain_token", "try_getpass", - ] +] -from getpass import ( - getpass, - getuser, -) -from socket import gethostname +from getpass import getpass import sys -from urllib.parse import urljoin - -import bs4 -import requests from .creds import Credentials @@ -44,61 +35,3 @@ def obtain_credentials(credentials): return Credentials.parse(credentials) else: return None - - -def obtain_token(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. - """ - url_login = urljoin(url, "../../accounts/login/") - url_token = urljoin(url, "account/") - - with requests.Session() as session: - - # Don't verify SSL/TLS certificates by default, if requested. - session.verify = not insecure - - # Fetch the log-in page. - response = session.get(url_login) - response.raise_for_status() - - # Extract the CSRF token. - login_doc = bs4.BeautifulSoup(response.content, "html.parser") - login_button = login_doc.find('button', text="Login") - login_form = login_button.findParent("form") - login_data = { - elem["name"]: elem["value"] for elem in login_form("input") - if elem.has_attr("name") and elem.has_attr("value") - } - login_data["username"] = username - login_data["password"] = password - # The following `requester` field is not used (at the time of - # writing) but it ought to be associated with this new token so - # that tokens can be selectively revoked at a later date. - login_data["requester"] = "%s@%s" % (getuser(), gethostname()) - - # Log-in to MAAS. - response = session.post(url_login, login_data) - response.raise_for_status() - - # Request a new API token. - create_data = { - "csrfmiddlewaretoken": session.cookies["csrftoken"], - "op": "create_authorisation_token", - } - create_headers = { - "Accept": "application/json", - } - response = session.post(url_token, create_data, create_headers) - response.raise_for_status() - - # We have it! - token = response.json() - return Credentials( - token["consumer_key"], - token["token_key"], - token["token_secret"], - ) diff --git a/setup.py b/setup.py index d7e8479..18cb6e6 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,6 @@ "oauthlib >= 1.0.3", "pytz >= 2014.10", "PyYAML >= 3.11", - "requests >= 2.9.1", "terminaltables >= 2.1.0", }, test_suite="maas.client", From 66a743708190a4d821cb836796db387e8a39a24b Mon Sep 17 00:00:00 2001 From: Fabian Baier Date: Tue, 7 Mar 2017 14:11:28 -0800 Subject: [PATCH 053/245] helpers.py fix in newer MAAS versions to find login button --- maas/client/bones/helpers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/maas/client/bones/helpers.py b/maas/client/bones/helpers.py index ca2f905..f6095c1 100644 --- a/maas/client/bones/helpers.py +++ b/maas/client/bones/helpers.py @@ -223,7 +223,11 @@ def check_response(response): login_doc = bs4.BeautifulSoup(login_doc_content, "html.parser") login_button = login_doc.find('button', text="Login") - login_form = login_button.findParent("form") + if login_button is None: + login_button = login_doc.find('input', value='Login') + login_form = login_button.findParent("form") + else: + login_form = login_button.findParent("form") # Log-in to MAAS. login_data = { From 665bf5958bca1d74558796bbfe4eb7bd39bbdce8 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 8 Mar 2017 10:23:00 +0000 Subject: [PATCH 054/245] Updated docs in preparation for an 0.4.0 release. --- doc.yaml | 2 ++ doc/bones/index.md | 2 -- doc/client/index.md | 38 +++++++++++++++++++++ doc/index.md | 78 +++++++++++++++++++++++++++++++++++--------- doc/viscera/index.md | 12 ++----- doc/viscera/nodes.md | 67 +++++++++++++++++++++++++------------ 6 files changed, 152 insertions(+), 47 deletions(-) create mode 100644 doc/client/index.md diff --git a/doc.yaml b/doc.yaml index cc63398..b992db4 100644 --- a/doc.yaml +++ b/doc.yaml @@ -10,6 +10,8 @@ theme: readthedocs use_directory_urls: false pages: - Home: index.md + - Client: + - Home: client/index.md - Bones: - Home: bones/index.md - Viscera: diff --git a/doc/bones/index.md b/doc/bones/index.md index 42e7e92..00704cf 100644 --- a/doc/bones/index.md +++ b/doc/bones/index.md @@ -13,10 +13,8 @@ _bones_ behind the scenes). 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") diff --git a/doc/client/index.md b/doc/client/index.md new file mode 100644 index 0000000..f6545bb --- /dev/null +++ b/doc/client/index.md @@ -0,0 +1,38 @@ +# The Web API client + +Calling ``maas.client.login`` or ``maas.client.connect`` 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.5 + +from maas.client import login + +client = login( + "http://localhost:5240/MAAS/", + username="foo", password="bar", +) + +# 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() +``` diff --git a/doc/index.md b/doc/index.md index e2a2662..62f608d 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,28 +1,56 @@ # Welcome to MAAS's new command-line tool & Python client libraries. For documentation on the MAAS server components, visit -[maas.ubuntu.com](https://maas.ubuntu.com/docs/). +[docs.ubuntu.com](https://docs.ubuntu.com/maas/). ## Command-line ```console $ bin/maas profiles login --help -$ bin/maas profiles login exmpl http://example.com:5240/MAAS/ my_username +$ 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 │ -└───────────────┴───────────┴───────────────┴───────┴────────┴───────────┴───────┘ +$ bin/maas list +┌───┬────────────┬───────────┬───────┬────────┬────────┬─────────┐ +│ │ Hostname │ System ID │ #CPUs │ RAM │ Status │ Power │ +├───┼────────────┼───────────┼───────┼────────┼────────┼─────────┤ +│ m │ botswana │ pncys4 │ 4 │ 8.0 GB │ Ready │ Off │ +│ c │ namibia │ xfaxgw │ 4 │ 8.0 GB │ — │ Error │ +│ C │ madagascar │ 4y3h7n │ 4 │ 8.0 GB │ — │ Unknown │ +└───┴────────────┴───────────┴───────┴────────┴────────┴─────────┘ ``` -## Client libraries +## Client library -There are two client libraries that make use of MAAS's Web API: +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, to print out a few recent events: + +```python +from maas.client import login +client = login( + "http://localhost:5240/MAAS/", + username="my_user", password="my_pass", +) +tmpl = ( + "{0.created:%Y-%m-%d %H:%M:%S} " + "{0.level.name} {0.description_short}" +) +for event in client.events.query(): + print(tmpl.format(event)) +``` + +Learn more about the primary [Web API client](client/index.md). + + +### _Bones_ & _viscera_ + +The primary client is based on two underlying client libraries: * 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 @@ -30,12 +58,30 @@ There are two client libraries that make use of MAAS's Web API: * 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. + _viscera_ presents a hand-crafted API specifically _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. - +[_bones_](bones/index.md). Try this next: [Get started with _viscera_](viscera/getting-started.md) + + +## Shell + +There's an interactive shell too. This imports some convenient bits into +the default namespace, and creates a _viscera_ ``Origin`` instance and a +_bones_ ``SessionAPI`` instance bound to the currently selected profile. + +For the best experience install [IPython](https://ipython.org/) first. + +```console +$ bin/maas shell +Welcome to the MAAS shell. +... +``` + +```pycon +>>> origin.Version.read() + +``` diff --git a/doc/viscera/index.md b/doc/viscera/index.md index feff504..82a0c12 100644 --- a/doc/viscera/index.md +++ b/doc/viscera/index.md @@ -7,10 +7,8 @@ #!/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") @@ -18,12 +16,8 @@ profile, origin = viscera.Origin.login( # 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)) +# List all machines. +print(">>> origin.Machines.read()") +pprint(origin.Machines.read()) ``` diff --git a/doc/viscera/nodes.md b/doc/viscera/nodes.md index 94f90af..f8f90a5 100644 --- a/doc/viscera/nodes.md +++ b/doc/viscera/nodes.md @@ -1,55 +1,82 @@ -# _Viscera_: Working with nodes +# _Viscera_: Working with machines, devices, racks, and regions +Given an ``Origin`` instance bound to your MAAS server, you can +interrogate your nodes with: -## Listing +```python +origin.Machines.read() + # returns an origin.Machines instance, a + # sequence of origin.Machine instances. + +origin.Devices.read() + # returns an origin.Devices instance, a + # sequence of origin.Device instances. + +origin.RackControllers.read() + # returns an origin.RackControllers instance, a + # sequence of origin.RackController instances. + +origin.RegionControllers.read() + # returns an origin.RegionControllers instance, a + # sequence of origin.RegionController instances. +``` + + +## An example ```pycon ->>> for node in origin.Nodes: +>>> for machine in origin.Machines.read(): ... print(repr(node)) - - + ``` Individual nodes can be read from the Web API. ```pycon ->>> node = origin.Node.read(system_id="433333") +>>> machine = origin.Machine.read(system_id="pncys4") +>>> machine + ``` -Nodes have many useful attributes: +Machines — and devices, racks, and regions — have many useful +attributes: ```pycon ->>> node.architecture +>>> machine.architecture 'amd64/generic' ->>> node.cpus +>>> 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(node)`` to find out what other fields and methods are available. +``dir(machine)`` to find out what other fields and methods are +available. __TODO__: Updating nodes. -## Acquiring and starting +## Allocating and deploying ```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 +>>> help(origin.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 :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) + associated with a matched machine. +>>> machine = origin.Machines.allocate(tags=("foo", "-bar")) +>>> print(machine.status_name) Acquired ->>> node.start() ->>> print(node.status_name) +>>> machine.deploy() +>>> print(machine.status_name) Deploying ``` From b6c5a7dcf2f8f4057d68a36aa62a429f8d506714 Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 8 Mar 2017 10:57:42 +0000 Subject: [PATCH 055/245] Update front matter for upcoming 0.4.0 release. --- README | 46 +++++++++++++++++++++++++++++++++++++--------- README.md | 50 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/README b/README index 229b073..8114136 100644 --- a/README +++ b/README @@ -2,18 +2,10 @@ python-libmaas ============== 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. +`MAAS `__. |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 ------------ @@ -39,6 +31,42 @@ the ``site`` directory. Recent documentation is also published to the `MAAS Client Library & CLI documentation `__ 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 + +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 `__ 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. + .. |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 diff --git a/README.md b/README.md index 661a05a..4d9b12f 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,10 @@ # 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. +Python client API library made especially for [MAAS][]. [![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 @@ -33,8 +25,42 @@ at least for now, it makes more sense to work directly from trunk. 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. +[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 + +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. + + +[MAAS]: https://maas.io/ +[docs]: http://maas.github.io/python-libmaas/ +[CCLA]: https://www.ubuntu.com/legal/contributors +[AGPLv3]: https://www.gnu.org/licenses/agpl-3.0.html -[1]: https://maas.ubuntu.com/ -[2]: http://maas.github.io/python-libmaas/ +[IPython]: https://ipython.org/ From dc4e622b049fcc5942e31a0ef8bc62b9aa2e958a Mon Sep 17 00:00:00 2001 From: Gavin Panella Date: Wed, 8 Mar 2017 12:33:30 +0000 Subject: [PATCH 056/245] Add an API description doc for MAAS 2.1, and prettify. --- Makefile | 15 +- maas/client/bones/testing/api20.json | 2732 +++++++++++++++++- maas/client/bones/testing/api20.raw.json | 1 + maas/client/bones/testing/api21.json | 3270 ++++++++++++++++++++++ maas/client/bones/testing/api21.raw.json | 1 + scripts/prettify-api-desc-doc | 25 + 6 files changed, 6042 insertions(+), 2 deletions(-) create mode 100644 maas/client/bones/testing/api20.raw.json create mode 100644 maas/client/bones/testing/api21.json create mode 100644 maas/client/bones/testing/api21.raw.json create mode 100755 scripts/prettify-api-desc-doc diff --git a/Makefile b/Makefile index 4523247..c1719ad 100644 --- a/Makefile +++ b/Makefile @@ -51,4 +51,17 @@ bin/mkdocs: bin/pip # --- -.PHONY: develop dist docs test integrate lint clean +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 integrate lint clean pretty diff --git a/maas/client/bones/testing/api20.json b/maas/client/bones/testing/api20.json index b4dac8b..6f2c7bb 100644 --- a/maas/client/bones/testing/api20.json +++ b/maas/client/bones/testing/api20.json @@ -1 +1,2731 @@ -{"doc": "MAAS API", "hash": "ad0d8bb110f4b629278ceaef279948b7cf33db41", "resources": [{"auth": {"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}/", "params": ["system_id", "interface_id"], "name": "InterfaceHandler", "doc": "Manage a node's or device's interface.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "InterfaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/machines/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/", "params": ["system_id"], "name": "MachineHandler", "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", "actions": [{"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "power_off", "op": "power_off", "restful": false, "method": "POST", "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."}, {"name": "query_power_state", "op": "query_power_state", "restful": false, "method": "GET", "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."}, {"name": "power_on", "op": "power_on", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "get_curtin_config", "op": "get_curtin_config", "restful": false, "method": "GET", "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."}, {"name": "abort", "op": "abort", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "commission", "op": "commission", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "set_storage_layout", "op": "set_storage_layout", "restful": false, "method": "POST", "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."}, {"name": "clear_default_gateways", "op": "clear_default_gateways", "restful": false, "method": "POST", "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."}, {"name": "deploy", "op": "deploy", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "MachineHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "params": ["system_id"], "name": "BlockDevicesHandler", "doc": "Manage block devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all block devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BlockDevicesHandler"}, {"auth": {"path": "/MAAS/api/2.0/subnets/{subnet_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/{subnet_id}/", "params": ["subnet_id"], "name": "SubnetHandler", "doc": "Manage subnet.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "reserved_ip_ranges", "op": "reserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently reserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "unreserved_ip_ranges", "op": "unreserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently unreserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "statistics", "op": "statistics", "restful": false, "method": "GET", "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."}, {"name": "ip_addresses", "op": "ip_addresses", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete subnet.\n\nReturns 404 if the subnet is not found."}]}, "anon": null, "name": "SubnetHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "InterfacesHandler", "doc": "Manage interfaces on a node or device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "InterfacesHandler"}, {"auth": {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "MachinesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "list_allocated", "op": "list_allocated", "restful": false, "method": "GET", "doc": "Fetch Machines that were allocated to the User/oauth token."}, {"name": "accept_all", "op": "accept_all", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "deployment_status", "op": "deployment_status", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "allocate", "op": "allocate", "restful": false, "method": "POST", "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."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "AnonMachinesHandler", "doc": "Anonymous access to Machines.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401."}]}, "name": "MachinesHandler"}, {"auth": {"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}/", "params": ["system_id", "device_id"], "name": "BlockDeviceHandler", "doc": "Manage a block device on a node.", "actions": [{"name": "set_boot_disk", "op": "set_boot_disk", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "add_tag", "op": "add_tag", "restful": false, "method": "GET", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read block device on node.\n\nReturns 404 if the node or block device is not found."}, {"name": "remove_tag", "op": "remove_tag", "restful": false, "method": "GET", "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."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "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."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "BlockDeviceHandler"}, {"auth": {"path": "/MAAS/api/2.0/subnets/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/", "params": [], "name": "SubnetsHandler", "doc": "Manage subnets.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all subnets."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "SubnetsHandler"}, {"auth": {"path": "/MAAS/api/2.0/users/", "uri": "http://localhost:5240/MAAS/api/2.0/users/", "params": [], "name": "UsersHandler", "doc": "Manage the user accounts of this MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List users."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "UsersHandler"}, {"auth": {"path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "params": ["osystem", "distro_series"], "name": "LicenseKeyHandler", "doc": "Manage a license key.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read license key."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete license key."}]}, "anon": null, "name": "LicenseKeyHandler"}, {"auth": {"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}/", "params": ["system_id", "interface_id"], "name": "NodeInterfaceHandler", "doc": "Manage a node's interface. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "NodeInterfaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/rackcontrollers/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/{system_id}/", "params": ["system_id"], "name": "RackControllerHandler", "doc": "Manage an individual rack controller.\n\nThe rack controller is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "refresh", "op": "refresh", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "RackControllerHandler"}, {"auth": {"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}", "params": ["system_id", "device_id", "partition_id"], "name": "PartitionHandler", "doc": "Manage partition on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read partition.\n\nReturns 404 if the node, block device, or partition are not found."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "doc": "Unformat a partition."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete partition.\n\nReturns 404 if the node, block device, or partition are not found."}]}, "anon": null, "name": "PartitionHandler"}, {"auth": {"path": "/MAAS/api/2.0/maas/", "uri": "http://localhost:5240/MAAS/api/2.0/maas/", "params": [], "name": "MaasHandler", "doc": "Manage the MAAS server.", "actions": [{"name": "get_config", "op": "get_config", "restful": false, "method": "GET", "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)."}, {"name": "set_config", "op": "set_config", "restful": false, "method": "POST", "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)."}]}, "anon": null, "name": "MaasHandler"}, {"auth": {"path": "/MAAS/api/2.0/zones/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/{name}/", "params": ["name"], "name": "ZoneHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET request. Return zone.\n\nReturns 404 if the zone is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "PUT request. Update zone.\n\nReturns 404 if the zone is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "DELETE request. Delete zone.\n\nReturns 404 if the zone is not found.\nReturns 204 if the zone is successfully deleted."}]}, "anon": null, "name": "ZoneHandler"}, {"auth": {"path": "/MAAS/api/2.0/license-keys/", "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/", "params": [], "name": "LicenseKeysHandler", "doc": "Manage the license keys.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List license keys."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "LicenseKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-resources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/", "params": ["id"], "name": "BootResourceHandler", "doc": "Manage a boot resource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot resource."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete boot resource."}]}, "anon": null, "name": "BootResourceHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "NodeInterfacesHandler", "doc": "Manage interfaces on a node. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "NodeInterfacesHandler"}, {"auth": {"path": "/MAAS/api/2.0/rackcontrollers/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/", "params": [], "name": "RackControllersHandler", "doc": "Manage the collection of all rack controllers in MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, "name": "RackControllersHandler"}, {"auth": {"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/", "params": ["system_id", "device_id"], "name": "PartitionsHandler", "doc": "Manage partitions on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all partitions on the block device.\n\nReturns 404 if the node or the block device are not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "PartitionsHandler"}, {"auth": {"path": "/MAAS/api/2.0/commissioning-scripts/{name}", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}", "params": ["name"], "name": "CommissioningScriptHandler", "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a commissioning script."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update a commissioning script."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a commissioning script."}]}, "anon": null, "name": "CommissioningScriptHandler"}, {"auth": {"path": "/MAAS/api/2.0/zones/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/", "params": [], "name": "ZonesHandler", "doc": "Manage physical zones.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List zones.\n\nGet a listing of all the physical zones."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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"}]}, "anon": null, "name": "ZonesHandler"}, {"auth": {"path": "/MAAS/api/2.0/domains/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/", "params": [], "name": "DomainsHandler", "doc": "Manage domains.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all domains."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain."}]}, "anon": null, "name": "DomainsHandler"}, {"auth": {"path": "/MAAS/api/2.0/devices/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/", "params": ["system_id"], "name": "DeviceHandler", "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific device.\n\nReturns 404 if the device is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DeviceHandler"}, {"auth": {"path": "/MAAS/api/2.0/tags/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/{name}/", "params": ["name"], "name": "TagHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Tag.\n\nReturns 404 if the tag is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "rebuild", "op": "rebuild", "restful": false, "method": "POST", "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."}, {"name": "nodes", "op": "nodes", "restful": false, "method": "GET", "doc": "Get the list of nodes that have this tag.\n\nReturns 404 if the tag is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific Tag.\n\nReturns 404 if the tag is not found.\nReturns 204 if the tag is successfully deleted."}, {"name": "update_nodes", "op": "update_nodes", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "TagHandler"}, {"auth": {"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}/", "params": ["system_id", "volume_group_id"], "name": "VolumeGroupHandler", "doc": "Manage volume group on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read volume group on node.\n\nReturns 404 if the node or volume group is not found."}, {"name": "delete_logical_volume", "op": "delete_logical_volume", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "create_logical_volume", "op": "create_logical_volume", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "VolumeGroupHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-resources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/", "params": [], "name": "BootResourcesHandler", "doc": "Manage the boot resources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all"}, {"name": "import", "op": "import", "restful": false, "method": "POST", "doc": "Import the boot resources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootResourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/commissioning-scripts/", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/", "params": [], "name": "CommissioningScriptsHandler", "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List commissioning scripts."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "CommissioningScriptsHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/", "params": ["fabric_id"], "name": "FabricHandler", "doc": "Manage fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found."}]}, "anon": null, "name": "FabricHandler"}, {"auth": {"path": "/MAAS/api/2.0/events/", "uri": "http://localhost:5240/MAAS/api/2.0/events/", "params": [], "name": "EventsHandler", "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.", "actions": [{"name": "query", "op": "query", "restful": false, "method": "GET", "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."}]}, "anon": null, "name": "EventsHandler"}, {"auth": {"path": "/MAAS/api/2.0/devices/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/", "params": [], "name": "DevicesHandler", "doc": "Manage the collection of all the devices in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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"}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "DevicesHandler"}, {"auth": {"path": "/MAAS/api/2.0/tags/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/", "params": [], "name": "TagsHandler", "doc": "Manage the collection of all the Tags in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List Tags.\n\nGet a listing of all tags that are currently defined."}]}, "anon": null, "name": "TagsHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "params": ["system_id"], "name": "VolumeGroupsHandler", "doc": "Manage volume groups on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all volume groups belonging to a machine.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "VolumeGroupsHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-sources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/", "params": ["id"], "name": "BootSourceHandler", "doc": "Manage a boot source.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, "anon": null, "name": "BootSourceHandler"}, {"auth": {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "FilesHandler", "doc": "Manage the collection of all the files in this MAAS.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "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"}, {"name": "add", "op": "add", "restful": false, "method": "POST", "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"}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, "anon": {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "AnonFilesHandler", "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.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, "name": "FilesHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/", "params": [], "name": "FabricsHandler", "doc": "Manage fabrics.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fabrics."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric."}]}, "anon": null, "name": "FabricsHandler"}, {"auth": null, "anon": {"path": "/MAAS/api/2.0/version/", "uri": "http://localhost:5240/MAAS/api/2.0/version/", "params": [], "name": "VersionHandler", "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 }", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Version and capabilities of this MAAS instance."}]}, "name": "VersionHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "params": ["dnsresourcerecord_id"], "name": "DNSResourceRecordHandler", "doc": "Manage dnsresourcerecord.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DNSResourceRecordHandler"}, {"auth": {"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}/", "params": ["system_id", "raid_id"], "name": "RaidHandler", "doc": "Manage a specific RAID device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read RAID device on node.\n\nReturns 404 if the node or RAID is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete RAID on node.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready."}]}, "anon": null, "name": "RaidHandler"}, {"auth": {"path": "/MAAS/api/2.0/files/{filename}/", "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/", "params": ["filename"], "name": "FileHandler", "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "doc": "Delete a FileStorage object."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a FileStorage object."}]}, "anon": null, "name": "FileHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-sources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/", "params": [], "name": "BootSourcesHandler", "doc": "Manage the collection of boot sources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot sources.\n\nGet a listing of boot sources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootSourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "params": ["fannetwork_id"], "name": "FanNetworkHandler", "doc": "Manage Fan Network.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found."}]}, "anon": null, "name": "FanNetworkHandler"}, {"auth": {"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/", "params": ["system_id"], "name": "BcacheCacheSetsHandler", "doc": "Manage bcache cache sets on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache cache sets belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BcacheCacheSetsHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresourcerecords/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/", "params": [], "name": "DNSResourceRecordsHandler", "doc": "Manage dnsresourcerecords.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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.)"}]}, "anon": null, "name": "DNSResourceRecordsHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/raids/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raids/", "params": ["system_id"], "name": "RaidsHandler", "doc": "Manage all RAID devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all RAID devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "RaidsHandler"}, {"auth": {"path": "/MAAS/api/2.0/ipaddresses/", "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/", "params": [], "name": "IPAddressesHandler", "doc": "Manage IP addresses allocated by MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List IPAddresses.\n\nGet a listing of all IPAddresses allocated to the requesting user."}, {"name": "reserve", "op": "reserve", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "IPAddressesHandler"}, {"auth": {"path": "/MAAS/api/2.0/installation-results/", "uri": "http://localhost:5240/MAAS/api/2.0/installation-results/", "params": [], "name": "NodeResultsHandler", "doc": "Read the collection of NodeResult in the MAAS.", "actions": [{"name": "list", "op": "list", "restful": false, "method": "GET", "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"}]}, "anon": null, "name": "NodeResultsHandler"}, {"auth": {"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}/", "params": ["boot_source_id", "id"], "name": "BootSourceSelectionHandler", "doc": "Manage a boot source selection.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source selection."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, "anon": null, "name": "BootSourceSelectionHandler"}, {"auth": {"path": "/MAAS/api/2.0/fannetworks/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/", "params": [], "name": "FanNetworksHandler", "doc": "Manage Fan Networks.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fannetworks."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "FanNetworksHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "params": ["dnsresource_id"], "name": "DNSResourceHandler", "doc": "Manage dnsresource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DNSResourceHandler"}, {"auth": {"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}/", "params": ["system_id", "bcache_id"], "name": "BcacheHandler", "doc": "Manage bcache device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache device on node.\n\nReturns 404 if the node or bcache is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete bcache on node.\n\nReturns 404 if the node or bcache is not found.\nReturns 409 if the node is not Ready."}]}, "anon": null, "name": "BcacheHandler"}, {"auth": {"path": "/MAAS/api/2.0/networks/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/{name}/", "params": ["name"], "name": "NetworkHandler", "doc": "Manage a network.\n\nThis endpoint is deprecated. Use the new 'subnet' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read network definition."}, {"name": "list_connected_macs", "op": "list_connected_macs", "restful": false, "method": "GET", "doc": "Returns the list of MAC addresses connected to this network.\n\nOnly MAC addresses for nodes visible to the requesting user are\nreturned."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "connect_macs", "op": "connect_macs", "restful": false, "method": "POST", "doc": "Connect the given MAC addresses to this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "disconnect_macs", "op": "disconnect_macs", "restful": false, "method": "POST", "doc": "Disconnect the given MAC addresses from this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}]}, "anon": null, "name": "NetworkHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "params": ["keyid"], "name": "SSHKeyHandler", "doc": "Manage an SSH key.\n\nSSH keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET an SSH key.\n\nReturns 404 if the key does not exist."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "SSHKeyHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "params": ["fabric_id", "vid"], "name": "VlanHandler", "doc": "Manage VLAN on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}]}, "anon": null, "name": "VlanHandler"}, {"auth": {"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/", "params": ["boot_source_id"], "name": "BootSourceSelectionsHandler", "doc": "Manage the collection of boot source selections.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot source selections.\n\nGet a listing of a boot source's selections."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootSourceSelectionsHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresources/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/", "params": [], "name": "DNSResourcesHandler", "doc": "Manage dnsresources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "DNSResourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/", "params": ["system_id"], "name": "BcachesHandler", "doc": "Manage bcache devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BcachesHandler"}, {"auth": {"path": "/MAAS/api/2.0/networks/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/", "params": [], "name": "NetworksHandler", "doc": "Manage the networks.\n\nThis endpoint is deprecated. Use the new 'subnets' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Define a network.\n\nThis endpoint is no longer available. Use the 'subnets' endpoint\ninstead."}]}, "anon": null, "name": "NetworksHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sshkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/", "params": [], "name": "SSHKeysHandler", "doc": "Manage the collection of all the SSH keys in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, "anon": null, "name": "SSHKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "params": ["fabric_id"], "name": "VlansHandler", "doc": "Manage VLANs on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all VLANs belonging to fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN."}]}, "anon": null, "name": "VlansHandler"}, {"auth": {"path": "/MAAS/api/2.0/domains/{domain_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/{domain_id}/", "params": ["domain_id"], "name": "DomainHandler", "doc": "Manage domain.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read domain.\n\nReturns 404 if the domain is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DomainHandler"}, {"auth": {"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}/", "params": ["system_id", "cache_set_id"], "name": "BcacheCacheSetHandler", "doc": "Manage bcache cache set on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache cache set on node.\n\nReturns 404 if the node or cache set is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "BcacheCacheSetHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/", "params": ["system_id"], "name": "NodeHandler", "doc": "Manage an individual Node.\n\nThe Node is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "NodeHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "params": ["keyid"], "name": "SSLKeyHandler", "doc": "Manage an SSL key.\n\nSSL keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "delete", "op": "delete", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "SSLKeyHandler"}, {"auth": {"path": "/MAAS/api/2.0/spaces/{space_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/{space_id}/", "params": ["space_id"], "name": "SpaceHandler", "doc": "Manage space.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read space.\n\nReturns 404 if the space is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update space.\n\n:param name: Name of the space.\n\nReturns 404 if the space is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete space.\n\nReturns 404 if the space is not found."}]}, "anon": null, "name": "SpaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/", "uri": "http://localhost:5240/MAAS/api/2.0/account/", "params": [], "name": "AccountHandler", "doc": "Manage the current logged-in user.", "actions": [{"name": "delete_authorisation_token", "op": "delete_authorisation_token", "restful": false, "method": "POST", "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"}, {"name": "create_authorisation_token", "op": "create_authorisation_token", "restful": false, "method": "POST", "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)"}]}, "anon": null, "name": "AccountHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "NodesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, "name": "NodesHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sslkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/", "params": [], "name": "SSLKeysHandler", "doc": "Operations on multiple keys.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, "anon": null, "name": "SSLKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/spaces/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/", "params": [], "name": "SpacesHandler", "doc": "Manage spaces.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all spaces."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a space.\n\n:param name: Name of the space."}]}, "anon": null, "name": "SpacesHandler"}], "handlers": [{"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "AnonMachinesHandler", "doc": "Anonymous access to Machines.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401."}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "AnonFilesHandler", "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.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/version/", "uri": "http://localhost:5240/MAAS/api/2.0/version/", "params": [], "name": "VersionHandler", "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 }", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Version and capabilities of this MAAS instance."}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, {"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}/", "params": ["system_id", "interface_id"], "name": "InterfaceHandler", "doc": "Manage a node's or device's interface.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/machines/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/", "params": ["system_id"], "name": "MachineHandler", "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", "actions": [{"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "power_off", "op": "power_off", "restful": false, "method": "POST", "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."}, {"name": "query_power_state", "op": "query_power_state", "restful": false, "method": "GET", "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."}, {"name": "power_on", "op": "power_on", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "get_curtin_config", "op": "get_curtin_config", "restful": false, "method": "GET", "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."}, {"name": "abort", "op": "abort", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "commission", "op": "commission", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "set_storage_layout", "op": "set_storage_layout", "restful": false, "method": "POST", "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."}, {"name": "clear_default_gateways", "op": "clear_default_gateways", "restful": false, "method": "POST", "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."}, {"name": "deploy", "op": "deploy", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "params": ["system_id"], "name": "BlockDevicesHandler", "doc": "Manage block devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all block devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/subnets/{subnet_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/{subnet_id}/", "params": ["subnet_id"], "name": "SubnetHandler", "doc": "Manage subnet.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "reserved_ip_ranges", "op": "reserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently reserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "unreserved_ip_ranges", "op": "unreserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently unreserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "statistics", "op": "statistics", "restful": false, "method": "GET", "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."}, {"name": "ip_addresses", "op": "ip_addresses", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete subnet.\n\nReturns 404 if the subnet is not found."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "InterfacesHandler", "doc": "Manage interfaces on a node or device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "MachinesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "list_allocated", "op": "list_allocated", "restful": false, "method": "GET", "doc": "Fetch Machines that were allocated to the User/oauth token."}, {"name": "accept_all", "op": "accept_all", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "deployment_status", "op": "deployment_status", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "allocate", "op": "allocate", "restful": false, "method": "POST", "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."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "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."}]}, {"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}/", "params": ["system_id", "device_id"], "name": "BlockDeviceHandler", "doc": "Manage a block device on a node.", "actions": [{"name": "set_boot_disk", "op": "set_boot_disk", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "add_tag", "op": "add_tag", "restful": false, "method": "GET", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read block device on node.\n\nReturns 404 if the node or block device is not found."}, {"name": "remove_tag", "op": "remove_tag", "restful": false, "method": "GET", "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."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "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."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/subnets/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/", "params": [], "name": "SubnetsHandler", "doc": "Manage subnets.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all subnets."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/users/", "uri": "http://localhost:5240/MAAS/api/2.0/users/", "params": [], "name": "UsersHandler", "doc": "Manage the user accounts of this MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List users."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "params": ["osystem", "distro_series"], "name": "LicenseKeyHandler", "doc": "Manage a license key.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read license key."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete license key."}]}, {"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}/", "params": ["system_id", "interface_id"], "name": "NodeInterfaceHandler", "doc": "Manage a node's interface. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/rackcontrollers/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/{system_id}/", "params": ["system_id"], "name": "RackControllerHandler", "doc": "Manage an individual rack controller.\n\nThe rack controller is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "refresh", "op": "refresh", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}", "params": ["system_id", "device_id", "partition_id"], "name": "PartitionHandler", "doc": "Manage partition on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read partition.\n\nReturns 404 if the node, block device, or partition are not found."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "doc": "Unformat a partition."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete partition.\n\nReturns 404 if the node, block device, or partition are not found."}]}, {"path": "/MAAS/api/2.0/maas/", "uri": "http://localhost:5240/MAAS/api/2.0/maas/", "params": [], "name": "MaasHandler", "doc": "Manage the MAAS server.", "actions": [{"name": "get_config", "op": "get_config", "restful": false, "method": "GET", "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)."}, {"name": "set_config", "op": "set_config", "restful": false, "method": "POST", "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)."}]}, {"path": "/MAAS/api/2.0/zones/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/{name}/", "params": ["name"], "name": "ZoneHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET request. Return zone.\n\nReturns 404 if the zone is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "PUT request. Update zone.\n\nReturns 404 if the zone is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "DELETE request. Delete zone.\n\nReturns 404 if the zone is not found.\nReturns 204 if the zone is successfully deleted."}]}, {"path": "/MAAS/api/2.0/license-keys/", "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/", "params": [], "name": "LicenseKeysHandler", "doc": "Manage the license keys.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List license keys."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-resources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/", "params": ["id"], "name": "BootResourceHandler", "doc": "Manage a boot resource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot resource."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete boot resource."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "NodeInterfacesHandler", "doc": "Manage interfaces on a node. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/rackcontrollers/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/", "params": [], "name": "RackControllersHandler", "doc": "Manage the collection of all rack controllers in MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, {"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/", "params": ["system_id", "device_id"], "name": "PartitionsHandler", "doc": "Manage partitions on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all partitions on the block device.\n\nReturns 404 if the node or the block device are not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/commissioning-scripts/{name}", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}", "params": ["name"], "name": "CommissioningScriptHandler", "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a commissioning script."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update a commissioning script."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a commissioning script."}]}, {"path": "/MAAS/api/2.0/zones/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/", "params": [], "name": "ZonesHandler", "doc": "Manage physical zones.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List zones.\n\nGet a listing of all the physical zones."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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"}]}, {"path": "/MAAS/api/2.0/domains/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/", "params": [], "name": "DomainsHandler", "doc": "Manage domains.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all domains."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain."}]}, {"path": "/MAAS/api/2.0/devices/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/", "params": ["system_id"], "name": "DeviceHandler", "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific device.\n\nReturns 404 if the device is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/tags/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/{name}/", "params": ["name"], "name": "TagHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Tag.\n\nReturns 404 if the tag is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "rebuild", "op": "rebuild", "restful": false, "method": "POST", "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."}, {"name": "nodes", "op": "nodes", "restful": false, "method": "GET", "doc": "Get the list of nodes that have this tag.\n\nReturns 404 if the tag is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific Tag.\n\nReturns 404 if the tag is not found.\nReturns 204 if the tag is successfully deleted."}, {"name": "update_nodes", "op": "update_nodes", "restful": false, "method": "POST", "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."}]}, {"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}/", "params": ["system_id", "volume_group_id"], "name": "VolumeGroupHandler", "doc": "Manage volume group on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read volume group on node.\n\nReturns 404 if the node or volume group is not found."}, {"name": "delete_logical_volume", "op": "delete_logical_volume", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "create_logical_volume", "op": "create_logical_volume", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-resources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/", "params": [], "name": "BootResourcesHandler", "doc": "Manage the boot resources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all"}, {"name": "import", "op": "import", "restful": false, "method": "POST", "doc": "Import the boot resources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/commissioning-scripts/", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/", "params": [], "name": "CommissioningScriptsHandler", "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List commissioning scripts."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/", "params": ["fabric_id"], "name": "FabricHandler", "doc": "Manage fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found."}]}, {"path": "/MAAS/api/2.0/events/", "uri": "http://localhost:5240/MAAS/api/2.0/events/", "params": [], "name": "EventsHandler", "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.", "actions": [{"name": "query", "op": "query", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/devices/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/", "params": [], "name": "DevicesHandler", "doc": "Manage the collection of all the devices in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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"}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/tags/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/", "params": [], "name": "TagsHandler", "doc": "Manage the collection of all the Tags in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List Tags.\n\nGet a listing of all tags that are currently defined."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "params": ["system_id"], "name": "VolumeGroupsHandler", "doc": "Manage volume groups on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all volume groups belonging to a machine.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-sources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/", "params": ["id"], "name": "BootSourceHandler", "doc": "Manage a boot source.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "FilesHandler", "doc": "Manage the collection of all the files in this MAAS.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "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"}, {"name": "add", "op": "add", "restful": false, "method": "POST", "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"}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/", "params": [], "name": "FabricsHandler", "doc": "Manage fabrics.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fabrics."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric."}]}, {"path": "/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "params": ["dnsresourcerecord_id"], "name": "DNSResourceRecordHandler", "doc": "Manage dnsresourcerecord.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "raid_id"], "name": "RaidHandler", "doc": "Manage a specific RAID device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read RAID device on node.\n\nReturns 404 if the node or RAID is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete RAID on node.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready."}]}, {"path": "/MAAS/api/2.0/files/{filename}/", "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/", "params": ["filename"], "name": "FileHandler", "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "doc": "Delete a FileStorage object."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a FileStorage object."}]}, {"path": "/MAAS/api/2.0/boot-sources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/", "params": [], "name": "BootSourcesHandler", "doc": "Manage the collection of boot sources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot sources.\n\nGet a listing of boot sources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "params": ["fannetwork_id"], "name": "FanNetworkHandler", "doc": "Manage Fan Network.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found."}]}, {"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/", "params": ["system_id"], "name": "BcacheCacheSetsHandler", "doc": "Manage bcache cache sets on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache cache sets belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresourcerecords/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/", "params": [], "name": "DNSResourceRecordsHandler", "doc": "Manage dnsresourcerecords.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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.)"}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/raids/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raids/", "params": ["system_id"], "name": "RaidsHandler", "doc": "Manage all RAID devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all RAID devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/ipaddresses/", "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/", "params": [], "name": "IPAddressesHandler", "doc": "Manage IP addresses allocated by MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List IPAddresses.\n\nGet a listing of all IPAddresses allocated to the requesting user."}, {"name": "reserve", "op": "reserve", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/installation-results/", "uri": "http://localhost:5240/MAAS/api/2.0/installation-results/", "params": [], "name": "NodeResultsHandler", "doc": "Read the collection of NodeResult in the MAAS.", "actions": [{"name": "list", "op": "list", "restful": false, "method": "GET", "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"}]}, {"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}/", "params": ["boot_source_id", "id"], "name": "BootSourceSelectionHandler", "doc": "Manage a boot source selection.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source selection."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, {"path": "/MAAS/api/2.0/fannetworks/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/", "params": [], "name": "FanNetworksHandler", "doc": "Manage Fan Networks.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fannetworks."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "params": ["dnsresource_id"], "name": "DNSResourceHandler", "doc": "Manage dnsresource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "bcache_id"], "name": "BcacheHandler", "doc": "Manage bcache device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache device on node.\n\nReturns 404 if the node or bcache is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete bcache on node.\n\nReturns 404 if the node or bcache is not found.\nReturns 409 if the node is not Ready."}]}, {"path": "/MAAS/api/2.0/networks/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/{name}/", "params": ["name"], "name": "NetworkHandler", "doc": "Manage a network.\n\nThis endpoint is deprecated. Use the new 'subnet' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read network definition."}, {"name": "list_connected_macs", "op": "list_connected_macs", "restful": false, "method": "GET", "doc": "Returns the list of MAC addresses connected to this network.\n\nOnly MAC addresses for nodes visible to the requesting user are\nreturned."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "connect_macs", "op": "connect_macs", "restful": false, "method": "POST", "doc": "Connect the given MAC addresses to this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "disconnect_macs", "op": "disconnect_macs", "restful": false, "method": "POST", "doc": "Disconnect the given MAC addresses from this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}]}, {"path": "/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "params": ["keyid"], "name": "SSHKeyHandler", "doc": "Manage an SSH key.\n\nSSH keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET an SSH key.\n\nReturns 404 if the key does not exist."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "params": ["fabric_id", "vid"], "name": "VlanHandler", "doc": "Manage VLAN on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}]}, {"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/", "params": ["boot_source_id"], "name": "BootSourceSelectionsHandler", "doc": "Manage the collection of boot source selections.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot source selections.\n\nGet a listing of a boot source's selections."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresources/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/", "params": [], "name": "DNSResourcesHandler", "doc": "Manage dnsresources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/", "params": ["system_id"], "name": "BcachesHandler", "doc": "Manage bcache devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/networks/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/", "params": [], "name": "NetworksHandler", "doc": "Manage the networks.\n\nThis endpoint is deprecated. Use the new 'subnets' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Define a network.\n\nThis endpoint is no longer available. Use the 'subnets' endpoint\ninstead."}]}, {"path": "/MAAS/api/2.0/account/prefs/sshkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/", "params": [], "name": "SSHKeysHandler", "doc": "Manage the collection of all the SSH keys in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "params": ["fabric_id"], "name": "VlansHandler", "doc": "Manage VLANs on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all VLANs belonging to fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN."}]}, {"path": "/MAAS/api/2.0/domains/{domain_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/{domain_id}/", "params": ["domain_id"], "name": "DomainHandler", "doc": "Manage domain.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read domain.\n\nReturns 404 if the domain is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "cache_set_id"], "name": "BcacheCacheSetHandler", "doc": "Manage bcache cache set on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache cache set on node.\n\nReturns 404 if the node or cache set is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/", "params": ["system_id"], "name": "NodeHandler", "doc": "Manage an individual Node.\n\nThe Node is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "params": ["keyid"], "name": "SSLKeyHandler", "doc": "Manage an SSL key.\n\nSSL keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "delete", "op": "delete", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/spaces/{space_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/{space_id}/", "params": ["space_id"], "name": "SpaceHandler", "doc": "Manage space.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read space.\n\nReturns 404 if the space is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update space.\n\n:param name: Name of the space.\n\nReturns 404 if the space is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete space.\n\nReturns 404 if the space is not found."}]}, {"path": "/MAAS/api/2.0/account/", "uri": "http://localhost:5240/MAAS/api/2.0/account/", "params": [], "name": "AccountHandler", "doc": "Manage the current logged-in user.", "actions": [{"name": "delete_authorisation_token", "op": "delete_authorisation_token", "restful": false, "method": "POST", "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"}, {"name": "create_authorisation_token", "op": "create_authorisation_token", "restful": false, "method": "POST", "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)"}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "NodesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/account/prefs/sslkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/", "params": [], "name": "SSLKeysHandler", "doc": "Operations on multiple keys.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, {"path": "/MAAS/api/2.0/spaces/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/", "params": [], "name": "SpacesHandler", "doc": "Manage spaces.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all spaces."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a space.\n\n:param name: Name of the space."}]}]} \ No newline at end of file +{ + "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/testing/api20.raw.json b/maas/client/bones/testing/api20.raw.json new file mode 100644 index 0000000..b4dac8b --- /dev/null +++ b/maas/client/bones/testing/api20.raw.json @@ -0,0 +1 @@ +{"doc": "MAAS API", "hash": "ad0d8bb110f4b629278ceaef279948b7cf33db41", "resources": [{"auth": {"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}/", "params": ["system_id", "interface_id"], "name": "InterfaceHandler", "doc": "Manage a node's or device's interface.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "InterfaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/machines/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/", "params": ["system_id"], "name": "MachineHandler", "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", "actions": [{"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "power_off", "op": "power_off", "restful": false, "method": "POST", "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."}, {"name": "query_power_state", "op": "query_power_state", "restful": false, "method": "GET", "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."}, {"name": "power_on", "op": "power_on", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "get_curtin_config", "op": "get_curtin_config", "restful": false, "method": "GET", "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."}, {"name": "abort", "op": "abort", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "commission", "op": "commission", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "set_storage_layout", "op": "set_storage_layout", "restful": false, "method": "POST", "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."}, {"name": "clear_default_gateways", "op": "clear_default_gateways", "restful": false, "method": "POST", "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."}, {"name": "deploy", "op": "deploy", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "MachineHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "params": ["system_id"], "name": "BlockDevicesHandler", "doc": "Manage block devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all block devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BlockDevicesHandler"}, {"auth": {"path": "/MAAS/api/2.0/subnets/{subnet_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/{subnet_id}/", "params": ["subnet_id"], "name": "SubnetHandler", "doc": "Manage subnet.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "reserved_ip_ranges", "op": "reserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently reserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "unreserved_ip_ranges", "op": "unreserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently unreserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "statistics", "op": "statistics", "restful": false, "method": "GET", "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."}, {"name": "ip_addresses", "op": "ip_addresses", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete subnet.\n\nReturns 404 if the subnet is not found."}]}, "anon": null, "name": "SubnetHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "InterfacesHandler", "doc": "Manage interfaces on a node or device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "InterfacesHandler"}, {"auth": {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "MachinesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "list_allocated", "op": "list_allocated", "restful": false, "method": "GET", "doc": "Fetch Machines that were allocated to the User/oauth token."}, {"name": "accept_all", "op": "accept_all", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "deployment_status", "op": "deployment_status", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "allocate", "op": "allocate", "restful": false, "method": "POST", "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."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "AnonMachinesHandler", "doc": "Anonymous access to Machines.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401."}]}, "name": "MachinesHandler"}, {"auth": {"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}/", "params": ["system_id", "device_id"], "name": "BlockDeviceHandler", "doc": "Manage a block device on a node.", "actions": [{"name": "set_boot_disk", "op": "set_boot_disk", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "add_tag", "op": "add_tag", "restful": false, "method": "GET", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read block device on node.\n\nReturns 404 if the node or block device is not found."}, {"name": "remove_tag", "op": "remove_tag", "restful": false, "method": "GET", "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."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "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."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "BlockDeviceHandler"}, {"auth": {"path": "/MAAS/api/2.0/subnets/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/", "params": [], "name": "SubnetsHandler", "doc": "Manage subnets.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all subnets."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "SubnetsHandler"}, {"auth": {"path": "/MAAS/api/2.0/users/", "uri": "http://localhost:5240/MAAS/api/2.0/users/", "params": [], "name": "UsersHandler", "doc": "Manage the user accounts of this MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List users."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "UsersHandler"}, {"auth": {"path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "params": ["osystem", "distro_series"], "name": "LicenseKeyHandler", "doc": "Manage a license key.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read license key."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete license key."}]}, "anon": null, "name": "LicenseKeyHandler"}, {"auth": {"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}/", "params": ["system_id", "interface_id"], "name": "NodeInterfaceHandler", "doc": "Manage a node's interface. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "NodeInterfaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/rackcontrollers/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/{system_id}/", "params": ["system_id"], "name": "RackControllerHandler", "doc": "Manage an individual rack controller.\n\nThe rack controller is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "refresh", "op": "refresh", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "RackControllerHandler"}, {"auth": {"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}", "params": ["system_id", "device_id", "partition_id"], "name": "PartitionHandler", "doc": "Manage partition on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read partition.\n\nReturns 404 if the node, block device, or partition are not found."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "doc": "Unformat a partition."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete partition.\n\nReturns 404 if the node, block device, or partition are not found."}]}, "anon": null, "name": "PartitionHandler"}, {"auth": {"path": "/MAAS/api/2.0/maas/", "uri": "http://localhost:5240/MAAS/api/2.0/maas/", "params": [], "name": "MaasHandler", "doc": "Manage the MAAS server.", "actions": [{"name": "get_config", "op": "get_config", "restful": false, "method": "GET", "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)."}, {"name": "set_config", "op": "set_config", "restful": false, "method": "POST", "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)."}]}, "anon": null, "name": "MaasHandler"}, {"auth": {"path": "/MAAS/api/2.0/zones/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/{name}/", "params": ["name"], "name": "ZoneHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET request. Return zone.\n\nReturns 404 if the zone is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "PUT request. Update zone.\n\nReturns 404 if the zone is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "DELETE request. Delete zone.\n\nReturns 404 if the zone is not found.\nReturns 204 if the zone is successfully deleted."}]}, "anon": null, "name": "ZoneHandler"}, {"auth": {"path": "/MAAS/api/2.0/license-keys/", "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/", "params": [], "name": "LicenseKeysHandler", "doc": "Manage the license keys.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List license keys."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "LicenseKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-resources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/", "params": ["id"], "name": "BootResourceHandler", "doc": "Manage a boot resource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot resource."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete boot resource."}]}, "anon": null, "name": "BootResourceHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "NodeInterfacesHandler", "doc": "Manage interfaces on a node. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "NodeInterfacesHandler"}, {"auth": {"path": "/MAAS/api/2.0/rackcontrollers/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/", "params": [], "name": "RackControllersHandler", "doc": "Manage the collection of all rack controllers in MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, "name": "RackControllersHandler"}, {"auth": {"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/", "params": ["system_id", "device_id"], "name": "PartitionsHandler", "doc": "Manage partitions on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all partitions on the block device.\n\nReturns 404 if the node or the block device are not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "PartitionsHandler"}, {"auth": {"path": "/MAAS/api/2.0/commissioning-scripts/{name}", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}", "params": ["name"], "name": "CommissioningScriptHandler", "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a commissioning script."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update a commissioning script."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a commissioning script."}]}, "anon": null, "name": "CommissioningScriptHandler"}, {"auth": {"path": "/MAAS/api/2.0/zones/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/", "params": [], "name": "ZonesHandler", "doc": "Manage physical zones.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List zones.\n\nGet a listing of all the physical zones."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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"}]}, "anon": null, "name": "ZonesHandler"}, {"auth": {"path": "/MAAS/api/2.0/domains/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/", "params": [], "name": "DomainsHandler", "doc": "Manage domains.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all domains."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain."}]}, "anon": null, "name": "DomainsHandler"}, {"auth": {"path": "/MAAS/api/2.0/devices/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/", "params": ["system_id"], "name": "DeviceHandler", "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific device.\n\nReturns 404 if the device is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DeviceHandler"}, {"auth": {"path": "/MAAS/api/2.0/tags/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/{name}/", "params": ["name"], "name": "TagHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Tag.\n\nReturns 404 if the tag is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "rebuild", "op": "rebuild", "restful": false, "method": "POST", "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."}, {"name": "nodes", "op": "nodes", "restful": false, "method": "GET", "doc": "Get the list of nodes that have this tag.\n\nReturns 404 if the tag is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific Tag.\n\nReturns 404 if the tag is not found.\nReturns 204 if the tag is successfully deleted."}, {"name": "update_nodes", "op": "update_nodes", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "TagHandler"}, {"auth": {"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}/", "params": ["system_id", "volume_group_id"], "name": "VolumeGroupHandler", "doc": "Manage volume group on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read volume group on node.\n\nReturns 404 if the node or volume group is not found."}, {"name": "delete_logical_volume", "op": "delete_logical_volume", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "create_logical_volume", "op": "create_logical_volume", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "VolumeGroupHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-resources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/", "params": [], "name": "BootResourcesHandler", "doc": "Manage the boot resources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all"}, {"name": "import", "op": "import", "restful": false, "method": "POST", "doc": "Import the boot resources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootResourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/commissioning-scripts/", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/", "params": [], "name": "CommissioningScriptsHandler", "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List commissioning scripts."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "CommissioningScriptsHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/", "params": ["fabric_id"], "name": "FabricHandler", "doc": "Manage fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found."}]}, "anon": null, "name": "FabricHandler"}, {"auth": {"path": "/MAAS/api/2.0/events/", "uri": "http://localhost:5240/MAAS/api/2.0/events/", "params": [], "name": "EventsHandler", "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.", "actions": [{"name": "query", "op": "query", "restful": false, "method": "GET", "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."}]}, "anon": null, "name": "EventsHandler"}, {"auth": {"path": "/MAAS/api/2.0/devices/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/", "params": [], "name": "DevicesHandler", "doc": "Manage the collection of all the devices in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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"}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "DevicesHandler"}, {"auth": {"path": "/MAAS/api/2.0/tags/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/", "params": [], "name": "TagsHandler", "doc": "Manage the collection of all the Tags in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List Tags.\n\nGet a listing of all tags that are currently defined."}]}, "anon": null, "name": "TagsHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "params": ["system_id"], "name": "VolumeGroupsHandler", "doc": "Manage volume groups on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all volume groups belonging to a machine.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "VolumeGroupsHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-sources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/", "params": ["id"], "name": "BootSourceHandler", "doc": "Manage a boot source.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, "anon": null, "name": "BootSourceHandler"}, {"auth": {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "FilesHandler", "doc": "Manage the collection of all the files in this MAAS.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "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"}, {"name": "add", "op": "add", "restful": false, "method": "POST", "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"}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, "anon": {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "AnonFilesHandler", "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.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, "name": "FilesHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/", "params": [], "name": "FabricsHandler", "doc": "Manage fabrics.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fabrics."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric."}]}, "anon": null, "name": "FabricsHandler"}, {"auth": null, "anon": {"path": "/MAAS/api/2.0/version/", "uri": "http://localhost:5240/MAAS/api/2.0/version/", "params": [], "name": "VersionHandler", "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 }", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Version and capabilities of this MAAS instance."}]}, "name": "VersionHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "params": ["dnsresourcerecord_id"], "name": "DNSResourceRecordHandler", "doc": "Manage dnsresourcerecord.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DNSResourceRecordHandler"}, {"auth": {"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}/", "params": ["system_id", "raid_id"], "name": "RaidHandler", "doc": "Manage a specific RAID device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read RAID device on node.\n\nReturns 404 if the node or RAID is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete RAID on node.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready."}]}, "anon": null, "name": "RaidHandler"}, {"auth": {"path": "/MAAS/api/2.0/files/{filename}/", "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/", "params": ["filename"], "name": "FileHandler", "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "doc": "Delete a FileStorage object."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a FileStorage object."}]}, "anon": null, "name": "FileHandler"}, {"auth": {"path": "/MAAS/api/2.0/boot-sources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/", "params": [], "name": "BootSourcesHandler", "doc": "Manage the collection of boot sources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot sources.\n\nGet a listing of boot sources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootSourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "params": ["fannetwork_id"], "name": "FanNetworkHandler", "doc": "Manage Fan Network.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found."}]}, "anon": null, "name": "FanNetworkHandler"}, {"auth": {"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/", "params": ["system_id"], "name": "BcacheCacheSetsHandler", "doc": "Manage bcache cache sets on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache cache sets belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BcacheCacheSetsHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresourcerecords/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/", "params": [], "name": "DNSResourceRecordsHandler", "doc": "Manage dnsresourcerecords.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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.)"}]}, "anon": null, "name": "DNSResourceRecordsHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/raids/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raids/", "params": ["system_id"], "name": "RaidsHandler", "doc": "Manage all RAID devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all RAID devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "RaidsHandler"}, {"auth": {"path": "/MAAS/api/2.0/ipaddresses/", "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/", "params": [], "name": "IPAddressesHandler", "doc": "Manage IP addresses allocated by MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List IPAddresses.\n\nGet a listing of all IPAddresses allocated to the requesting user."}, {"name": "reserve", "op": "reserve", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}]}, "anon": null, "name": "IPAddressesHandler"}, {"auth": {"path": "/MAAS/api/2.0/installation-results/", "uri": "http://localhost:5240/MAAS/api/2.0/installation-results/", "params": [], "name": "NodeResultsHandler", "doc": "Read the collection of NodeResult in the MAAS.", "actions": [{"name": "list", "op": "list", "restful": false, "method": "GET", "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"}]}, "anon": null, "name": "NodeResultsHandler"}, {"auth": {"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}/", "params": ["boot_source_id", "id"], "name": "BootSourceSelectionHandler", "doc": "Manage a boot source selection.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source selection."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, "anon": null, "name": "BootSourceSelectionHandler"}, {"auth": {"path": "/MAAS/api/2.0/fannetworks/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/", "params": [], "name": "FanNetworksHandler", "doc": "Manage Fan Networks.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fannetworks."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "FanNetworksHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "params": ["dnsresource_id"], "name": "DNSResourceHandler", "doc": "Manage dnsresource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DNSResourceHandler"}, {"auth": {"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}/", "params": ["system_id", "bcache_id"], "name": "BcacheHandler", "doc": "Manage bcache device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache device on node.\n\nReturns 404 if the node or bcache is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete bcache on node.\n\nReturns 404 if the node or bcache is not found.\nReturns 409 if the node is not Ready."}]}, "anon": null, "name": "BcacheHandler"}, {"auth": {"path": "/MAAS/api/2.0/networks/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/{name}/", "params": ["name"], "name": "NetworkHandler", "doc": "Manage a network.\n\nThis endpoint is deprecated. Use the new 'subnet' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read network definition."}, {"name": "list_connected_macs", "op": "list_connected_macs", "restful": false, "method": "GET", "doc": "Returns the list of MAC addresses connected to this network.\n\nOnly MAC addresses for nodes visible to the requesting user are\nreturned."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "connect_macs", "op": "connect_macs", "restful": false, "method": "POST", "doc": "Connect the given MAC addresses to this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "disconnect_macs", "op": "disconnect_macs", "restful": false, "method": "POST", "doc": "Disconnect the given MAC addresses from this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}]}, "anon": null, "name": "NetworkHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "params": ["keyid"], "name": "SSHKeyHandler", "doc": "Manage an SSH key.\n\nSSH keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET an SSH key.\n\nReturns 404 if the key does not exist."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "SSHKeyHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "params": ["fabric_id", "vid"], "name": "VlanHandler", "doc": "Manage VLAN on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}]}, "anon": null, "name": "VlanHandler"}, {"auth": {"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/", "params": ["boot_source_id"], "name": "BootSourceSelectionsHandler", "doc": "Manage the collection of boot source selections.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot source selections.\n\nGet a listing of a boot source's selections."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BootSourceSelectionsHandler"}, {"auth": {"path": "/MAAS/api/2.0/dnsresources/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/", "params": [], "name": "DNSResourcesHandler", "doc": "Manage dnsresources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "DNSResourcesHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/", "params": ["system_id"], "name": "BcachesHandler", "doc": "Manage bcache devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, "anon": null, "name": "BcachesHandler"}, {"auth": {"path": "/MAAS/api/2.0/networks/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/", "params": [], "name": "NetworksHandler", "doc": "Manage the networks.\n\nThis endpoint is deprecated. Use the new 'subnets' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Define a network.\n\nThis endpoint is no longer available. Use the 'subnets' endpoint\ninstead."}]}, "anon": null, "name": "NetworksHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sshkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/", "params": [], "name": "SSHKeysHandler", "doc": "Manage the collection of all the SSH keys in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, "anon": null, "name": "SSHKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "params": ["fabric_id"], "name": "VlansHandler", "doc": "Manage VLANs on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all VLANs belonging to fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN."}]}, "anon": null, "name": "VlansHandler"}, {"auth": {"path": "/MAAS/api/2.0/domains/{domain_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/{domain_id}/", "params": ["domain_id"], "name": "DomainHandler", "doc": "Manage domain.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read domain.\n\nReturns 404 if the domain is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "DomainHandler"}, {"auth": {"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}/", "params": ["system_id", "cache_set_id"], "name": "BcacheCacheSetHandler", "doc": "Manage bcache cache set on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache cache set on node.\n\nReturns 404 if the node or cache set is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "BcacheCacheSetHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/", "params": ["system_id"], "name": "NodeHandler", "doc": "Manage an individual Node.\n\nThe Node is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "NodeHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "params": ["keyid"], "name": "SSLKeyHandler", "doc": "Manage an SSL key.\n\nSSL keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "delete", "op": "delete", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, "anon": null, "name": "SSLKeyHandler"}, {"auth": {"path": "/MAAS/api/2.0/spaces/{space_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/{space_id}/", "params": ["space_id"], "name": "SpaceHandler", "doc": "Manage space.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read space.\n\nReturns 404 if the space is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update space.\n\n:param name: Name of the space.\n\nReturns 404 if the space is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete space.\n\nReturns 404 if the space is not found."}]}, "anon": null, "name": "SpaceHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/", "uri": "http://localhost:5240/MAAS/api/2.0/account/", "params": [], "name": "AccountHandler", "doc": "Manage the current logged-in user.", "actions": [{"name": "delete_authorisation_token", "op": "delete_authorisation_token", "restful": false, "method": "POST", "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"}, {"name": "create_authorisation_token", "op": "create_authorisation_token", "restful": false, "method": "POST", "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)"}]}, "anon": null, "name": "AccountHandler"}, {"auth": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "NodesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, "anon": {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, "name": "NodesHandler"}, {"auth": {"path": "/MAAS/api/2.0/account/prefs/sslkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/", "params": [], "name": "SSLKeysHandler", "doc": "Operations on multiple keys.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, "anon": null, "name": "SSLKeysHandler"}, {"auth": {"path": "/MAAS/api/2.0/spaces/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/", "params": [], "name": "SpacesHandler", "doc": "Manage spaces.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all spaces."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a space.\n\n:param name: Name of the space."}]}, "anon": null, "name": "SpacesHandler"}], "handlers": [{"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "AnonMachinesHandler", "doc": "Anonymous access to Machines.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "doc": "Accept a machine's enlistment: not allowed to anonymous users.\n\nAlways returns 401."}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "AnonFilesHandler", "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.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/version/", "uri": "http://localhost:5240/MAAS/api/2.0/version/", "params": [], "name": "VersionHandler", "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 }", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Version and capabilities of this MAAS instance."}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "AnonNodesHandler", "doc": "Anonymous access to Nodes.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": null}, {"name": "is_registered", "op": "is_registered", "restful": false, "method": "GET", "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."}]}, {"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}/", "params": ["system_id", "interface_id"], "name": "InterfaceHandler", "doc": "Manage a node's or device's interface.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/machines/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/{system_id}/", "params": ["system_id"], "name": "MachineHandler", "doc": "Manage an individual Machine.\n\nThe Machine is identified by its system_id.", "actions": [{"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "power_off", "op": "power_off", "restful": false, "method": "POST", "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."}, {"name": "query_power_state", "op": "query_power_state", "restful": false, "method": "GET", "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."}, {"name": "power_on", "op": "power_on", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "get_curtin_config", "op": "get_curtin_config", "restful": false, "method": "GET", "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."}, {"name": "abort", "op": "abort", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "commission", "op": "commission", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "set_storage_layout", "op": "set_storage_layout", "restful": false, "method": "POST", "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."}, {"name": "clear_default_gateways", "op": "clear_default_gateways", "restful": false, "method": "POST", "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."}, {"name": "deploy", "op": "deploy", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/blockdevices/", "params": ["system_id"], "name": "BlockDevicesHandler", "doc": "Manage block devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all block devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/subnets/{subnet_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/{subnet_id}/", "params": ["subnet_id"], "name": "SubnetHandler", "doc": "Manage subnet.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "reserved_ip_ranges", "op": "reserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently reserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "unreserved_ip_ranges", "op": "unreserved_ip_ranges", "restful": false, "method": "GET", "doc": "Lists IP ranges currently unreserved in the subnet.\n\nReturns 404 if the subnet is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "statistics", "op": "statistics", "restful": false, "method": "GET", "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."}, {"name": "ip_addresses", "op": "ip_addresses", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete subnet.\n\nReturns 404 if the subnet is not found."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "InterfacesHandler", "doc": "Manage interfaces on a node or device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/machines/", "uri": "http://localhost:5240/MAAS/api/2.0/machines/", "params": [], "name": "MachinesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "list_allocated", "op": "list_allocated", "restful": false, "method": "GET", "doc": "Fetch Machines that were allocated to the User/oauth token."}, {"name": "accept_all", "op": "accept_all", "restful": false, "method": "POST", "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."}, {"name": "power_parameters", "op": "power_parameters", "restful": false, "method": "GET", "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."}, {"name": "deployment_status", "op": "deployment_status", "restful": false, "method": "GET", "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."}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "allocate", "op": "allocate", "restful": false, "method": "POST", "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."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}, {"name": "accept", "op": "accept", "restful": false, "method": "POST", "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."}]}, {"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}/", "params": ["system_id", "device_id"], "name": "BlockDeviceHandler", "doc": "Manage a block device on a node.", "actions": [{"name": "set_boot_disk", "op": "set_boot_disk", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "add_tag", "op": "add_tag", "restful": false, "method": "GET", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read block device on node.\n\nReturns 404 if the node or block device is not found."}, {"name": "remove_tag", "op": "remove_tag", "restful": false, "method": "GET", "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."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "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."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/subnets/", "uri": "http://localhost:5240/MAAS/api/2.0/subnets/", "params": [], "name": "SubnetsHandler", "doc": "Manage subnets.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all subnets."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/users/", "uri": "http://localhost:5240/MAAS/api/2.0/users/", "params": [], "name": "UsersHandler", "doc": "Manage the user accounts of this MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List users."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "uri": "http://localhost:5240/MAAS/api/2.0/license-key/{osystem}/{distro_series}", "params": ["osystem", "distro_series"], "name": "LicenseKeyHandler", "doc": "Manage a license key.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read license key."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete license key."}]}, {"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}/", "params": ["system_id", "interface_id"], "name": "NodeInterfaceHandler", "doc": "Manage a node's interface. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "set_default_gateway", "op": "set_default_gateway", "restful": false, "method": "POST", "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."}, {"name": "link_subnet", "op": "link_subnet", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete interface on node.\n\nReturns 404 if the node or interface is not found."}, {"name": "unlink_subnet", "op": "unlink_subnet", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/rackcontrollers/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/{system_id}/", "params": ["system_id"], "name": "RackControllerHandler", "doc": "Manage an individual rack controller.\n\nThe rack controller is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "refresh", "op": "refresh", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}", "params": ["system_id", "device_id", "partition_id"], "name": "PartitionHandler", "doc": "Manage partition on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read partition.\n\nReturns 404 if the node, block device, or partition are not found."}, {"name": "unformat", "op": "unformat", "restful": false, "method": "POST", "doc": "Unformat a partition."}, {"name": "mount", "op": "mount", "restful": false, "method": "POST", "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."}, {"name": "unmount", "op": "unmount", "restful": false, "method": "POST", "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."}, {"name": "format", "op": "format", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete partition.\n\nReturns 404 if the node, block device, or partition are not found."}]}, {"path": "/MAAS/api/2.0/maas/", "uri": "http://localhost:5240/MAAS/api/2.0/maas/", "params": [], "name": "MaasHandler", "doc": "Manage the MAAS server.", "actions": [{"name": "get_config", "op": "get_config", "restful": false, "method": "GET", "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)."}, {"name": "set_config", "op": "set_config", "restful": false, "method": "POST", "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)."}]}, {"path": "/MAAS/api/2.0/zones/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/{name}/", "params": ["name"], "name": "ZoneHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET request. Return zone.\n\nReturns 404 if the zone is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "PUT request. Update zone.\n\nReturns 404 if the zone is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "DELETE request. Delete zone.\n\nReturns 404 if the zone is not found.\nReturns 204 if the zone is successfully deleted."}]}, {"path": "/MAAS/api/2.0/license-keys/", "uri": "http://localhost:5240/MAAS/api/2.0/license-keys/", "params": [], "name": "LicenseKeysHandler", "doc": "Manage the license keys.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List license keys."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-resources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/{id}/", "params": ["id"], "name": "BootResourceHandler", "doc": "Manage a boot resource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot resource."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete boot resource."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/interfaces/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/interfaces/", "params": ["system_id"], "name": "NodeInterfacesHandler", "doc": "Manage interfaces on a node. (Deprecated)", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all interfaces belonging to a machine, device, or\nrack controller.\n\nReturns 404 if the node is not found."}, {"name": "create_physical", "op": "create_physical", "restful": false, "method": "POST", "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."}, {"name": "create_bond", "op": "create_bond", "restful": false, "method": "POST", "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."}, {"name": "create_vlan", "op": "create_vlan", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/rackcontrollers/", "uri": "http://localhost:5240/MAAS/api/2.0/rackcontrollers/", "params": [], "name": "RackControllersHandler", "doc": "Manage the collection of all rack controllers in MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, {"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/", "params": ["system_id", "device_id"], "name": "PartitionsHandler", "doc": "Manage partitions on a block device.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all partitions on the block device.\n\nReturns 404 if the node or the block device are not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/commissioning-scripts/{name}", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/{name}", "params": ["name"], "name": "CommissioningScriptHandler", "doc": "Manage a custom commissioning script.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a commissioning script."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update a commissioning script."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a commissioning script."}]}, {"path": "/MAAS/api/2.0/zones/", "uri": "http://localhost:5240/MAAS/api/2.0/zones/", "params": [], "name": "ZonesHandler", "doc": "Manage physical zones.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List zones.\n\nGet a listing of all the physical zones."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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"}]}, {"path": "/MAAS/api/2.0/domains/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/", "params": [], "name": "DomainsHandler", "doc": "Manage domains.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all domains."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a domain.\n\n:param name: Name of the domain.\n:param authoritative: Class type of the domain."}]}, {"path": "/MAAS/api/2.0/devices/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/{system_id}/", "params": ["system_id"], "name": "DeviceHandler", "doc": "Manage an individual device.\n\nThe device is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific device.\n\nReturns 404 if the device is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/tags/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/{name}/", "params": ["name"], "name": "TagHandler", "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.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Tag.\n\nReturns 404 if the tag is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "rebuild", "op": "rebuild", "restful": false, "method": "POST", "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."}, {"name": "nodes", "op": "nodes", "restful": false, "method": "GET", "doc": "Get the list of nodes that have this tag.\n\nReturns 404 if the tag is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific Tag.\n\nReturns 404 if the tag is not found.\nReturns 204 if the tag is successfully deleted."}, {"name": "update_nodes", "op": "update_nodes", "restful": false, "method": "POST", "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."}]}, {"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}/", "params": ["system_id", "volume_group_id"], "name": "VolumeGroupHandler", "doc": "Manage volume group on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read volume group on node.\n\nReturns 404 if the node or volume group is not found."}, {"name": "delete_logical_volume", "op": "delete_logical_volume", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}, {"name": "create_logical_volume", "op": "create_logical_volume", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-resources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-resources/", "params": [], "name": "BootResourcesHandler", "doc": "Manage the boot resources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all boot resources.\n\n:param type: Type of boot resources to list. Default: all"}, {"name": "import", "op": "import", "restful": false, "method": "POST", "doc": "Import the boot resources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/commissioning-scripts/", "uri": "http://localhost:5240/MAAS/api/2.0/commissioning-scripts/", "params": [], "name": "CommissioningScriptsHandler", "doc": "Manage custom commissioning scripts.\n\nThis functionality is only available to administrators.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List commissioning scripts."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/", "params": ["fabric_id"], "name": "FabricHandler", "doc": "Manage fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fabric.\n\nReturns 404 if the fabric is not found."}]}, {"path": "/MAAS/api/2.0/events/", "uri": "http://localhost:5240/MAAS/api/2.0/events/", "params": [], "name": "EventsHandler", "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.", "actions": [{"name": "query", "op": "query", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/devices/", "uri": "http://localhost:5240/MAAS/api/2.0/devices/", "params": [], "name": "DevicesHandler", "doc": "Manage the collection of all the devices in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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"}, {"name": "create", "op": "create", "restful": false, "method": "POST", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/tags/", "uri": "http://localhost:5240/MAAS/api/2.0/tags/", "params": [], "name": "TagsHandler", "doc": "Manage the collection of all the Tags in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List Tags.\n\nGet a listing of all tags that are currently defined."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/volume-groups/", "params": ["system_id"], "name": "VolumeGroupsHandler", "doc": "Manage volume groups on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all volume groups belonging to a machine.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/boot-sources/{id}/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/{id}/", "params": ["id"], "name": "BootSourceHandler", "doc": "Manage a boot source.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, {"path": "/MAAS/api/2.0/files/", "uri": "http://localhost:5240/MAAS/api/2.0/files/", "params": [], "name": "FilesHandler", "doc": "Manage the collection of all the files in this MAAS.", "actions": [{"name": "get", "op": "get", "restful": false, "method": "GET", "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."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "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"}, {"name": "add", "op": "add", "restful": false, "method": "POST", "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"}, {"name": "get_by_key", "op": "get_by_key", "restful": false, "method": "GET", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/", "params": [], "name": "FabricsHandler", "doc": "Manage fabrics.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fabrics."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a fabric.\n\n:param name: Name of the fabric.\n:param class_type: Class type of the fabric."}]}, {"path": "/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/{dnsresourcerecord_id}/", "params": ["dnsresourcerecord_id"], "name": "DNSResourceRecordHandler", "doc": "Manage dnsresourcerecord.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresourcerecord.\n\nReturns 404 if the dnsresourcerecord is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "raid_id"], "name": "RaidHandler", "doc": "Manage a specific RAID device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read RAID device on node.\n\nReturns 404 if the node or RAID is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete RAID on node.\n\nReturns 404 if the node or RAID is not found.\nReturns 409 if the node is not Ready."}]}, {"path": "/MAAS/api/2.0/files/{filename}/", "uri": "http://localhost:5240/MAAS/api/2.0/files/{filename}/", "params": ["filename"], "name": "FileHandler", "doc": "Manage a FileStorage object.\n\nThe file is identified by its filename and owner.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET a FileStorage object as a json object.\n\nThe 'content' of the file is base64-encoded."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "doc": "Delete a FileStorage object."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a FileStorage object."}]}, {"path": "/MAAS/api/2.0/boot-sources/", "uri": "http://localhost:5240/MAAS/api/2.0/boot-sources/", "params": [], "name": "BootSourcesHandler", "doc": "Manage the collection of boot sources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot sources.\n\nGet a listing of boot sources."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/{fannetwork_id}/", "params": ["fannetwork_id"], "name": "FanNetworkHandler", "doc": "Manage Fan Network.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read fannetwork.\n\nReturns 404 if the fannetwork is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete fannetwork.\n\nReturns 404 if the fannetwork is not found."}]}, {"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/", "params": ["system_id"], "name": "BcacheCacheSetsHandler", "doc": "Manage bcache cache sets on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache cache sets belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresourcerecords/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresourcerecords/", "params": [], "name": "DNSResourceRecordsHandler", "doc": "Manage dnsresourcerecords.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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.)"}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/raids/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/raids/", "params": ["system_id"], "name": "RaidsHandler", "doc": "Manage all RAID devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all RAID devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/ipaddresses/", "uri": "http://localhost:5240/MAAS/api/2.0/ipaddresses/", "params": [], "name": "IPAddressesHandler", "doc": "Manage IP addresses allocated by MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List IPAddresses.\n\nGet a listing of all IPAddresses allocated to the requesting user."}, {"name": "reserve", "op": "reserve", "restful": false, "method": "POST", "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."}, {"name": "release", "op": "release", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/installation-results/", "uri": "http://localhost:5240/MAAS/api/2.0/installation-results/", "params": [], "name": "NodeResultsHandler", "doc": "Read the collection of NodeResult in the MAAS.", "actions": [{"name": "list", "op": "list", "restful": false, "method": "GET", "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"}]}, {"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}/", "params": ["boot_source_id", "id"], "name": "BootSourceSelectionHandler", "doc": "Manage a boot source selection.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a boot source selection."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete a specific boot source."}]}, {"path": "/MAAS/api/2.0/fannetworks/", "uri": "http://localhost:5240/MAAS/api/2.0/fannetworks/", "params": [], "name": "FanNetworksHandler", "doc": "Manage Fan Networks.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all fannetworks."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/{dnsresource_id}/", "params": ["dnsresource_id"], "name": "DNSResourceHandler", "doc": "Manage dnsresource.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read dnsresource.\n\nReturns 404 if the dnsresource is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "bcache_id"], "name": "BcacheHandler", "doc": "Manage bcache device on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache device on node.\n\nReturns 404 if the node or bcache is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete bcache on node.\n\nReturns 404 if the node or bcache is not found.\nReturns 409 if the node is not Ready."}]}, {"path": "/MAAS/api/2.0/networks/{name}/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/{name}/", "params": ["name"], "name": "NetworkHandler", "doc": "Manage a network.\n\nThis endpoint is deprecated. Use the new 'subnet' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read network definition."}, {"name": "list_connected_macs", "op": "list_connected_macs", "restful": false, "method": "GET", "doc": "Returns the list of MAC addresses connected to this network.\n\nOnly MAC addresses for nodes visible to the requesting user are\nreturned."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "connect_macs", "op": "connect_macs", "restful": false, "method": "POST", "doc": "Connect the given MAC addresses to this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "disconnect_macs", "op": "disconnect_macs", "restful": false, "method": "POST", "doc": "Disconnect the given MAC addresses from this network.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete network definition.\n\nThis endpoint is no longer available. Use the 'subnet' endpoint\ninstead."}]}, {"path": "/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/{keyid}/", "params": ["keyid"], "name": "SSHKeyHandler", "doc": "Manage an SSH key.\n\nSSH keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "GET an SSH key.\n\nReturns 404 if the key does not exist."}, {"name": "delete", "op": "delete", "restful": false, "method": "POST", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/{vid}/", "params": ["fabric_id", "vid"], "name": "VlanHandler", "doc": "Manage VLAN on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete VLAN on fabric.\n\nReturns 404 if the fabric or VLAN is not found."}]}, {"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/", "params": ["boot_source_id"], "name": "BootSourceSelectionsHandler", "doc": "Manage the collection of boot source selections.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List boot source selections.\n\nGet a listing of a boot source's selections."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/dnsresources/", "uri": "http://localhost:5240/MAAS/api/2.0/dnsresources/", "params": [], "name": "DNSResourcesHandler", "doc": "Manage dnsresources.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/bcaches/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/bcaches/", "params": ["system_id"], "name": "BcachesHandler", "doc": "Manage bcache devices on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all bcache devices belonging to node.\n\nReturns 404 if the machine is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/networks/", "uri": "http://localhost:5240/MAAS/api/2.0/networks/", "params": [], "name": "NetworksHandler", "doc": "Manage the networks.\n\nThis endpoint is deprecated. Use the new 'subnets' endpoint instead.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Define a network.\n\nThis endpoint is no longer available. Use the 'subnets' endpoint\ninstead."}]}, {"path": "/MAAS/api/2.0/account/prefs/sshkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sshkeys/", "params": [], "name": "SSHKeysHandler", "doc": "Manage the collection of all the SSH keys in this MAAS.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, {"path": "/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "uri": "http://localhost:5240/MAAS/api/2.0/fabrics/{fabric_id}/vlans/", "params": ["fabric_id"], "name": "VlansHandler", "doc": "Manage VLANs on a fabric.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all VLANs belonging to fabric.\n\nReturns 404 if the fabric is not found."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a VLAN.\n\n:param name: Name of the VLAN.\n:param vid: VLAN ID of the VLAN."}]}, {"path": "/MAAS/api/2.0/domains/{domain_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/domains/{domain_id}/", "params": ["domain_id"], "name": "DomainHandler", "doc": "Manage domain.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read domain.\n\nReturns 404 if the domain is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"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}/", "params": ["system_id", "cache_set_id"], "name": "BcacheCacheSetHandler", "doc": "Manage bcache cache set on a node.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read bcache cache set on node.\n\nReturns 404 if the node or cache set is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/nodes/{system_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/{system_id}/", "params": ["system_id"], "name": "NodeHandler", "doc": "Manage an individual Node.\n\nThe Node is identified by its system_id.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read a specific Node.\n\nReturns 404 if the node is not found."}, {"name": "mark_broken", "op": "mark_broken", "restful": false, "method": "POST", "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."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": null}, {"name": "mark_fixed", "op": "mark_fixed", "restful": false, "method": "POST", "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."}, {"name": "details", "op": "details", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/{keyid}/", "params": ["keyid"], "name": "SSLKeyHandler", "doc": "Manage an SSL key.\n\nSSL keys can be retrieved or deleted.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "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."}, {"name": "delete", "op": "delete", "restful": false, "method": "GET", "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."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "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."}]}, {"path": "/MAAS/api/2.0/spaces/{space_id}/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/{space_id}/", "params": ["space_id"], "name": "SpaceHandler", "doc": "Manage space.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "Read space.\n\nReturns 404 if the space is not found."}, {"name": "update", "op": null, "restful": true, "method": "PUT", "doc": "Update space.\n\n:param name: Name of the space.\n\nReturns 404 if the space is not found."}, {"name": "delete", "op": null, "restful": true, "method": "DELETE", "doc": "Delete space.\n\nReturns 404 if the space is not found."}]}, {"path": "/MAAS/api/2.0/account/", "uri": "http://localhost:5240/MAAS/api/2.0/account/", "params": [], "name": "AccountHandler", "doc": "Manage the current logged-in user.", "actions": [{"name": "delete_authorisation_token", "op": "delete_authorisation_token", "restful": false, "method": "POST", "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"}, {"name": "create_authorisation_token", "op": "create_authorisation_token", "restful": false, "method": "POST", "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)"}]}, {"path": "/MAAS/api/2.0/nodes/", "uri": "http://localhost:5240/MAAS/api/2.0/nodes/", "params": [], "name": "NodesHandler", "doc": "Manage the collection of all the nodes in the MAAS.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all nodes."}, {"name": "set_zone", "op": "set_zone", "restful": false, "method": "POST", "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."}]}, {"path": "/MAAS/api/2.0/account/prefs/sslkeys/", "uri": "http://localhost:5240/MAAS/api/2.0/account/prefs/sslkeys/", "params": [], "name": "SSLKeysHandler", "doc": "Operations on multiple keys.", "actions": [{"name": "new", "op": "new", "restful": false, "method": "POST", "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\"."}, {"name": "list", "op": "list", "restful": false, "method": "GET", "doc": "List all keys belonging to the requesting user."}]}, {"path": "/MAAS/api/2.0/spaces/", "uri": "http://localhost:5240/MAAS/api/2.0/spaces/", "params": [], "name": "SpacesHandler", "doc": "Manage spaces.", "actions": [{"name": "read", "op": null, "restful": true, "method": "GET", "doc": "List all spaces."}, {"name": "create", "op": null, "restful": true, "method": "POST", "doc": "Create a space.\n\n:param name: Name of the space."}]}]} \ No newline at end of file diff --git a/maas/client/bones/testing/api21.json b/maas/client/bones/testing/api21.json new file mode 100644 index 0000000..314b497 --- /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