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