Library objects#
Collections#
These are the base data structures used in EnOSlib. They aren’t meant to be used directly.
Classes:
|
Wrapper around a Set exposing also some lists' operations. |
|
RolesDict is a way to group resources of the same type together using tags. |
- class enoslib.collections.ResourcesSet(iterable: Iterable | None = None)#
Wrapper around a Set exposing also some lists’ operations.
Items of the Set must be comparable and hashable.
It’s possible for instance to call
append
,extend
, etc. Indexing comes for instance with some caveats however:resource_set[0]
will give you the first resource in the alphabetical order not the first inserted machine as you’d expect with a regular list.- add(value)#
Add an element.
- discard(value)#
Remove an element. Do not raise an exception if absent.
- class enoslib.collections.RolesDict(dict=None, /, **kwargs)#
RolesDict is a way to group resources of the same type together using tags.
From the user perspective, a RolesDict’s instance
roles
is a dictionary. To retrieve all the corresponding machine with the tagtag
one can use ̀`roles[tag]`.The value associated with a tag behaves like a set (it’s a py:class:~enoslib.collections.ResourcesSet). So classical set operations are possible, for instance
roles[tag1] & roles[tag2]
will give you back the set of resources that are both tagged withtag1
andtag2
.This set also accepts some list operations (as it seems that users are more familiar with them). So it’s possible to call
append
,extend
, etc. Indexing comes with some caveats however:roles["tag"][0]
will give you the first resource in the alphabetical order associated with the tag ``tag``(not the first inserted machine as you’d expect with a regular list).- inner#
alias of
ResourcesSet
Resource abstractions#
These modules are made of the library-level objects. These are provider agnostic objects that can be fed into most of the EnOSlib functions.
Currently, the main abstractions of this module are the
Host
and the Network
.
They abstract away the notion of compute servers (something you can access and
run some actions on) and networks (something you can get IPs from). Grouping
resources is done using the Roles
and
Networks
(plural).
Most likely you’ll interact with Roles
and Networks
right after calling
provider.init()
: this is indeed a provider responsibility to turn your
abstract resource description into concrete library level objects.
Classes:
|
Good enough implementation of Network for most situations. |
|
Abstract unit of computation. |
|
A specialization of |
|
Base class for the library level network abstraction. |
|
A specialization of |
|
A specialization of |
|
A specialization of |
- class enoslib.objects.DefaultNetwork(address: bytes | int | str | IPv4Network | IPv6Network, gateway: str | None = None, dns: str | None = None, ip_start: bytes | int | str | IPv4Address | IPv6Address | None = None, ip_end: bytes | int | str | IPv4Address | IPv6Address | None = None, mac_start: str | None = None, mac_end: str | None = None)#
Good enough implementation of Network for most situations.
Provides pooling for contiguous ips and/or macs. Support IPv4 and IPv6.
Providers must inherit from this class.
- Parameters:
address – network address (as in ipaddress.ip_interface)
gateway – (optional) the gateway for this network (as in ipaddress.ip_address)
dns – (optional) the dns address (as in ipaddress.ip_address)
ip_start – (optional) first ip in the ip pool (as in ipaddress.ip_address)
ip_end – (optional) last ip in the ip pool (as in ipaddress.ip_address)
mac_start – (optional) first mac in the mac pool (as in netaddr.EUI)
mac_end – (optional) last mac in the mac pool (as in netaddr.EUI)
- class enoslib.objects.Host(address: str, alias: str | None = None, user: str | None = None, keyfile: str | None = None, port: int | None = None, extra: ~typing.Dict = <factory>, net_devices: ~typing.Set[~enoslib.objects.NetDevice] = <factory>)#
Abstract unit of computation.
A Host is anything EnosLib can access (e.g. using SSH) to and run shell commands on. It is an abstraction notion of unit of computation that can be bound to bare-metal machines, virtual machines, or containers.
Note
Internally EnOSlib is using Ansible to connect to the remote hosts. By default, SSH is used but it isn’t the only connection method supported. You can change the connection method to fit your needs by setting the ansible_connection key in the extra field (and other options if needed). Ref: https://docs.ansible.com/ansible/latest/plugins/connection.html
- Parameters:
address – host will be reached at this address (using SSH by default).
alias – a human-readable alias
user – user to connect with (e.g. using SSH)
keyfile – keyfile to use to authenticate (e.g. when using SSH)
port – port to connect to (e.g. using SSH)
extra – dictionary of options. Will be passed to Ansible as host_vars. Mutation of this attribute is possible and must be performed using the
set_extra()
orreset_extra()
net_devices – list of network devices configured on this host. can be synced with
sync_info()
.
Note
In the future we’d like the provider to populate the net_devices to get a consistent initial representation of the hosts.
- filter_addresses(networks: Iterable[Network] | None = None, include_unknown: bool = False) List[IPAddress] #
Get some addresses assigned to this host.
- Parameters:
networks – a list of networks to further filter the request If None or [], all the interfaces with at least one network attached will be returned. This doesn’t return interfaces attached to network unknown from EnOSlib.
include_unknown – True iff we want all the interface that are not attached to an EnOSlib network. Ignored if
networks
is not None.
- Returns:
A list of addresses
- filter_interfaces(networks: Iterable[Network] | None = None, include_unknown: bool = False) List[str] #
Get some device interfaces.
- Parameters:
networks – a list of networks to further filter the request If None, all the interfaces with at least one network attached will be returned. This doesn’t return interfaces attached to network unknown from EnOSlib.
include_unknown – True iff we want all the interface that are not attached to an EnOSlib network. Ignored if
networks
is not None.
- Returns:
A list of interface names.
- get_extra() Dict #
Get a copy of the extra vars of this host.
- class enoslib.objects.HostsView(iterable: Iterable | None = None)#
A specialization of
ResourcesSet
for
Host
.
- class enoslib.objects.Network(address: bytes | int | str | IPv4Network | IPv6Network)#
Base class for the library level network abstraction.
When one calls init on a provider, one takes ownership on nodes and networks. This class reflect one network owned by the user for the experiment lifetime. IPv4 and IPv6 networks can be represented by such object.
Providers must inherit from this class or the
DefaultNetwork
class which provides a good enough implementation in most cases.Indeed, currently provenance (which provider created this) is encoded in the __class__ attribute.
- class enoslib.objects.Networks(dict=None, /, **kwargs)#
A specialization of
RolesDict
for
NetworksView
.- inner#
alias of
NetworksView
Local#
Classes:
|
Representation of a local machine. |
- class enoslib.local.LocalHost(alias: str = 'localhost')#
Representation of a local machine.
- Parameters:
alias – alias for a local machine must be unique
Docker#
Manage remote docker containers as first class citizens.
A possible workflow would be to start your containers using the method of
your choice and build the list of available dockers using the
enoslib.docker.get_dockers()
function.
A DockerHost
is a specialization of a Host
and thus can be fed into
any Host related operations (play_on, run_command…) [1]. Hosts
datastructure in enoslib are tied somehow to Ansible. DockerHost is shaped so
that the docker connection plugin can run. So we inject at build time the
necessary connection options (ansible_connection=docker
,
ansible_docker_extra_args="-H <remote_docker>"
).
Connections to remote docker daemons can be made using different protocols [2].
- Using ssh: requires ssh access to remote host but
can go through a bastion host if .ssh/config is configured correctly. Note that the docker client must be available.
- Using raw tcp: requires to reach the remote docker daemon (e.g. be inside
g5k). Note that in this case the remote socket must be exposed.
Additionally, the structure is compatible with mitogen and its delegation model [3] which can improve the performance. Note that the facts from the host machines (where the docker daemon runs) needs to be gathered. One way to ensure this is to explicitly gather the facts from such hosts.
Example
1"""
2Example that makes use of the DockerHost data structure.
3
4This is an advanced example where
5- docker containers will be started on g5k machines
6- network emulation will be enforced between those docker containers by
7reusing |enoslib| api functions.
8"""
9import logging
10from pathlib import Path
11
12import enoslib as en
13
14en.init_logging(level=logging.INFO)
15en.check()
16
17job_name = Path(__file__).name
18
19
20conf = (
21 en.G5kConf.from_settings(job_name=job_name, walltime="0:30:00", job_type=[])
22 .add_machine(roles=["control"], cluster="econome", nodes=2)
23 .finalize()
24)
25
26provider = en.G5k(conf)
27
28# Get actual resources
29roles, networks = provider.init()
30
31# Install docker
32registry_opts = dict(type="external", ip="docker-cache.grid5000.fr", port=80)
33d = en.Docker(
34 agent=roles["control"], bind_var_docker="/tmp/docker", registry_opts=registry_opts
35)
36d.deploy()
37
38# Start N containers on each G5K host (for a total of 2*N containers)
39N = 4
40with en.play_on(roles=roles) as p:
41 p.raw("modprobe ifb")
42 for i in range(N):
43 p.docker_container(
44 name=f"mydocker-{i}",
45 image="ubuntu",
46 state="started",
47 command="sleep 10d",
48 capabilities=["NET_ADMIN"],
49 )
50
51# Get all the docker containers running on all remote hosts
52dockers = en.get_dockers(roles=roles)
53
54# Build the network contraints to apply on the remote docker
55# We assume here the interface name in docker to be eth0
56sources = []
57for idx, host in enumerate(dockers):
58 delay = idx
59 print(f"{host.alias} <-> {delay}ms")
60 inbound = en.NetemOutConstraint(device="eth0", options=f"delay {delay}ms")
61 outbound = en.NetemInConstraint(device="eth0", options=f"delay {delay}ms")
62 sources.append(en.NetemInOutSource(host, constraints={inbound, outbound}))
63
64# This requires the Docker client to be installed on the local machine.
65# Also, it might not work well because SSH connections are handled by Docker.
66# See https://gitlab.inria.fr/discovery/enoslib/-/issues/163 for discussion
67with en.play_on(roles=dockers, gather_facts=False) as p:
68 # We can't use the 'apt' module because python is not installed in containers
69 p.raw("apt update && DEBIAN_FRONTEND=noninteractive apt install -qq -y iproute2")
70
71en.netem(sources)
Classes:
|
A kind of host reachable using docker protocol. |
Functions:
|
Get remote dockers hosts. |
- class enoslib.docker.DockerHost(alias: str, container_name: str, host: Host, proto: str | None = None, state: Mapping | None = None)#
A kind of host reachable using docker protocol.
- Parameters:
alias – unique name across the deployment
container_name – name of the docker container on the remote host
host – the host where the container can be found
proto – how to connect to the remote host (DockerHost.PROTO_TCP/DockerHost.PROTO_SSH) [Default DockerHost.PROTO_SSH]
state – dict representing the state as returned by
docker inspect
- classmethod from_state(state: Mapping, host: Host) DockerHost #
Build a DockerHost from a state json as returned by docker inspect.
- enoslib.docker.get_dockers(roles: Roles, pattern_hosts: str = '*', container_name: str = '.*') List[DockerHost] #
Get remote dockers hosts.
- Parameters:
roles – the roles as returned by
enoslib.infra.provider.Provider.init()
pattern_hosts – pattern to describe ansible hosts to target. see https://docs.ansible.com/ansible/latest/intro_patterns.html
container_name – name of the containers to look for. Regexp are supported as in filter option of docker inspect.
- Returns:
List of DockerHost matching the passed container_name