scripting API: node management¶
Scripting features for node management are available at
walt.client.api.nodes
:
(.venv) ~/experiment$ python3
>>> from walt.client import api
>>> api.nodes
< -- API submodule for WALT nodes --
methods:
- self.create_vnode(self, node_name): Create a virtual node
- self.get_nodes(self, node_set='all-nodes'): Return nodes of the platform
>
>>>
Creating a virtual node¶
>>> from walt.client import api
>>> vn23 = api.nodes.create_vnode('vn23')
Node vn23 is now booting your image "pc-image:latest".
Use `walt node boot vn23 <other-image>` if needed.
>>> vn23
< -- virtual node vn23 --
read-only attributes:
- self.booted: False
- self.config: <node configuration>
- self.device_type: 'node'
- self.gateway: ''
- self.image: <image pc-image>
- self.ip: '192.168.152.6'
- self.mac: '52:54:00:2b:d4:76'
- self.model: 'pc-x86-64'
- self.name: 'vn23'
- self.netmask: '255.255.255.0'
- self.owner: 'eduble' # yourself
- self.type: 'node'
- self.virtual: True
methods:
- self.boot(self, image, force=False): Boot the specified WalT image
- self.get_logs(self, realtime=False, history=None, timeout=-1): Iterate over historical or realtime logs
- self.reboot(self, force=False, hard_only=False): Reboot this node
- self.remove(self, force=False): Remove this virtual node
- self.rename(self, new_name, force=False): Rename this virtual node
- self.wait(self, timeout=-1): Wait until node is booted
>
>>>
Getting access to plaform nodes¶
Use api method api.nodes.get_nodes()
:
>>> nodes = api.nodes.get_nodes() # default is to get all nodes
>>> len(nodes)
9
>>> nodes = api.nodes.get_nodes('my-nodes')
>>> len(nodes)
6
>>> nodes = api.nodes.get_nodes('rpibp,vn23')
>>> len(nodes)
2
>>> nodes = api.nodes.get_nodes(['rpibp', 'vn23'])
>>> len(nodes)
2
>>> nodes
< -- Set of WalT nodes (2 items) --
methods:
- self.boot(self, image, force=False): Boot the specified image on all nodes of this set
- self.filter(self, **kwargs): Return the subset of nodes matching the given attributes
- self.get(self, k, default=None): Return item specified or default value if missing
- self.get_logs(self, realtime=False, history=None, timeout=-1): Iterate over historical or realtime logs
- self.items(self): Iterate over key & value pairs this set contains
- self.keys(self): Iterate over keys this set contains
- self.reboot(self, force=False, hard_only=False): Reboot all nodes of this set
- self.values(self): Iterate over values this set contains
- self.wait(self, timeout=-1): Wait until all nodes of this set are booted
sub-items:
- self['rpibp']: <node rpibp>
- self['vn23']: <virtual node vn23>
note: these sub-items are also accessible using self.<shortcut> for handy completion.
(use <obj>.<tab><tab> to list these shortcuts)
>
>>>
Working with node sets¶
Some API functions such as api.nodes.get_nodes()
return a set of
nodes. Sets of nodes provide the following features:
nodes in the set can be accessed by using their name (e.g.
nodes['rpibp']
);they provide group operations for all nodes of the set, such as
reboot()
,wait()
,get_logs()
functions;they provide a
filter()
method allowing to select nodes having given attribute values (e.g.nodes.filter(virtual=True, booted=True)
), and returning a new set of nodes;they provide the self-description features of API objects.
Here is a sample code which reboots all virtual nodes:
from walt.client import api
nodes = api.nodes.get_nodes()
nodes = nodes.filter(booted = True, virtual = True)
nodes.reboot()
Indeed the user is free to use regular python sets instead, such as in this example:
from walt.client import api
nodes = api.nodes.get_nodes()
nodes = set(n for n in nodes if n.booted and n.virtual)
for node in nodes:
node.reboot()
One can also group individual nodes into a set by using binary-or operators:
>>> from walt.client import api
>>> nodes = api.nodes.get_nodes()
>>> nodes = nodes['rpi2b'] | nodes['rpi3b-test'] | nodes['rpibp']
>>> nodes
< -- Set of WalT nodes (3 items) --
methods:
- self.boot(self, image, force=False): Boot the specified image on all nodes of this set
- self.filter(self, **kwargs): Return the subset of nodes matching the given attributes
- self.get(self, k, default=None): Return item specified or default value if missing
- self.items(self): Iterate over key & value pairs this set contains
- self.keys(self): Iterate over keys this set contains
- self.reboot(self, force=False, hard_only=False): Reboot all nodes of this set
- self.values(self): Iterate over values this set contains
- self.wait(self, timeout_secs=-1): Wait until all nodes of this set are booted
sub-items:
- self['rpi2b']: <node rpi2b>
- self['rpi3b-test']: <node rpi3b-test>
- self['rpibp']: <node rpibp>
note: these sub-items are also accessible using self.<shortcut> for handy completion.
(use <obj>.<tab><tab> to list these shortcuts)
>
>>>
Interacting with a given node¶
Interacting with a given node is pretty obvious, as shown in this interactive session:
>>> rpibp = nodes['rpibp']
>>> rpibp
< -- node rpibp --
read-only attributes:
- self.booted: True
- self.config: <node configuration>
- self.device_type: 'node'
- self.gateway: ''
- self.image: <default for rpi-b-plus nodes>
- self.ip: '192.168.152.3'
- self.mac: 'b8:27:eb:68:a2:df'
- self.model: 'rpi-b-plus'
- self.name: 'rpibp'
- self.netmask: '255.255.255.0'
- self.owner: 'waltplatform' # node is free
- self.type: 'node'
- self.virtual: False
methods:
- self.boot(self, image, force=False): Boot the specified WalT image
- self.forget(self, force=False): Forget this node
- self.get_logs(self, realtime=False, history=None, timeout=-1): Iterate over historical or realtime logs
- self.reboot(self, force=False, hard_only=False): Reboot this node
- self.rename(self, new_name, force=False): Rename this node
- self.wait(self, timeout=-1): Wait until node is booted
>
>>> rpibp.reboot()
Node rpibp: rebooted ok.
>>>
These operations can be automated in a script, for instance to emulate
walt node reboot <node-name>
:
import sys
from walt.client import api
if len(sys.argv) < 2:
sys.exit('Node name is missing.')
nodes = api.nodes.get_nodes()
node_name = sys.argv[1]
if node_name not in nodes:
sys.exit(f'Could not find node {node_name} on the platform!')
node = nodes[node_name]
node.reboot()
Booting a WalT image¶
Method <node>.boot()
allows to boot a WalT image on a single node:
>>> vn23.boot('pc-x86-64-test-suite')
Node vn23 will now boot pc-x86-64-test-suite.
Node vn23: rebooted ok.
>>>
Instead of specifying the image by its name, one can also specify an image object:
>>> images = api.images.get_images()
>>> test_suite_image = images['pc-x86-64-test-suite']
>>> vn23.boot(test_suite_image)
Node vn23 will now boot pc-x86-64-test-suite.
Node vn23: rebooted ok.
>>>
See walt help show scripting-images for more info about image objects.
Alternatively, method <set-of-nodes>.boot()
can also be used to boot
an image on several nodes at once.
Working with logs¶
Method <node>.get_logs()
is the same as api.logs.get_logs()
with
the parameter issuers
set to <node>
. See
walt help show scripting-logs for more info.