atex 0.7__py3-none-any.whl → 0.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- atex/cli/fmf.py +143 -0
- atex/cli/libvirt.py +127 -0
- atex/cli/testingfarm.py +35 -13
- atex/connection/__init__.py +13 -19
- atex/connection/podman.py +63 -0
- atex/connection/ssh.py +34 -52
- atex/executor/__init__.py +2 -0
- atex/executor/duration.py +60 -0
- atex/executor/executor.py +402 -0
- atex/executor/reporter.py +101 -0
- atex/{minitmt → executor}/scripts.py +37 -25
- atex/{minitmt → executor}/testcontrol.py +54 -42
- atex/fmf.py +237 -0
- atex/orchestrator/__init__.py +3 -59
- atex/orchestrator/aggregator.py +82 -134
- atex/orchestrator/orchestrator.py +385 -0
- atex/provision/__init__.py +74 -105
- atex/provision/libvirt/__init__.py +2 -24
- atex/provision/libvirt/libvirt.py +465 -0
- atex/provision/libvirt/locking.py +168 -0
- atex/provision/libvirt/setup-libvirt.sh +21 -1
- atex/provision/podman/__init__.py +1 -0
- atex/provision/podman/podman.py +274 -0
- atex/provision/testingfarm/__init__.py +2 -29
- atex/provision/testingfarm/api.py +123 -65
- atex/provision/testingfarm/testingfarm.py +234 -0
- atex/util/__init__.py +1 -6
- atex/util/libvirt.py +18 -0
- atex/util/log.py +31 -8
- atex/util/named_mapping.py +158 -0
- atex/util/path.py +16 -0
- atex/util/ssh_keygen.py +14 -0
- atex/util/threads.py +99 -0
- atex-0.9.dist-info/METADATA +178 -0
- atex-0.9.dist-info/RECORD +43 -0
- atex/cli/minitmt.py +0 -175
- atex/minitmt/__init__.py +0 -23
- atex/minitmt/executor.py +0 -348
- atex/minitmt/fmf.py +0 -202
- atex/provision/nspawn/README +0 -74
- atex/provision/podman/README +0 -59
- atex/provision/podman/host_container.sh +0 -74
- atex/provision/testingfarm/foo.py +0 -1
- atex-0.7.dist-info/METADATA +0 -102
- atex-0.7.dist-info/RECORD +0 -32
- {atex-0.7.dist-info → atex-0.9.dist-info}/WHEEL +0 -0
- {atex-0.7.dist-info → atex-0.9.dist-info}/entry_points.txt +0 -0
- {atex-0.7.dist-info → atex-0.9.dist-info}/licenses/COPYING.txt +0 -0
atex/provision/__init__.py
CHANGED
|
@@ -1,110 +1,94 @@
|
|
|
1
1
|
import importlib as _importlib
|
|
2
2
|
import pkgutil as _pkgutil
|
|
3
|
-
import threading as _threading
|
|
4
3
|
|
|
5
4
|
from .. import connection as _connection
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class Provisioner:
|
|
9
8
|
"""
|
|
10
|
-
A resource (machine/system) provider.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
res = Provisioner(...)
|
|
36
|
-
res.reserve()
|
|
37
|
-
conn = res.connection()
|
|
38
|
-
conn.connect()
|
|
39
|
-
conn.ssh('ls /')
|
|
40
|
-
conn.disconnect()
|
|
41
|
-
res.release()
|
|
42
|
-
|
|
43
|
-
# via a context manager
|
|
44
|
-
with Provisioner(...) as res:
|
|
45
|
-
with res.connection() as conn:
|
|
46
|
-
conn.ssh('ls /')
|
|
47
|
-
|
|
48
|
-
If a Provisioner class needs additional configuration, it should do so via
|
|
49
|
-
class (not instance) attributes, allowing it to be instantiated many times.
|
|
50
|
-
|
|
51
|
-
class ConfiguredProvisioner(Provisioner):
|
|
52
|
-
resource_hub = 'https://...'
|
|
53
|
-
login = 'joe'
|
|
54
|
-
|
|
55
|
-
# or dynamically
|
|
56
|
-
name = 'joe'
|
|
57
|
-
cls = type(
|
|
58
|
-
f'Provisioner_for_{name}',
|
|
59
|
-
(Provisioner,),
|
|
60
|
-
{'resource_hub': 'https://...', 'login': name},
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
These attributes can then be accessed from __init__ or any other function.
|
|
9
|
+
A remote resource (machine/system) provider.
|
|
10
|
+
|
|
11
|
+
The main interface is .get_remote() that returns a connected class Remote
|
|
12
|
+
instance for use by the user, to be .release()d when not needed anymore,
|
|
13
|
+
with Provisioner automatically getting a replacement for it, to be returned
|
|
14
|
+
via .get_remote() later.
|
|
15
|
+
|
|
16
|
+
p = Provisioner()
|
|
17
|
+
p.start()
|
|
18
|
+
remote = p.get_remote()
|
|
19
|
+
remote.cmd(["ls", "/"])
|
|
20
|
+
remote.release()
|
|
21
|
+
p.stop()
|
|
22
|
+
|
|
23
|
+
with Provisioner() as p:
|
|
24
|
+
remote = p.get_remote()
|
|
25
|
+
...
|
|
26
|
+
remote.release()
|
|
27
|
+
|
|
28
|
+
TODO: mention how a Provisioner always needs to take care of release all Remotes
|
|
29
|
+
when .stop()ped or when context terminates; even the ones handed over to
|
|
30
|
+
the user
|
|
31
|
+
|
|
32
|
+
Note that .stop() or .defer_stop() may be called from a different
|
|
33
|
+
thread, asynchronously to any other functions.
|
|
64
34
|
"""
|
|
65
35
|
|
|
66
|
-
def
|
|
36
|
+
def get_remote(self, block=True):
|
|
67
37
|
"""
|
|
68
|
-
|
|
69
|
-
|
|
38
|
+
Get a connected class Remote instance.
|
|
39
|
+
|
|
40
|
+
If 'block' is True, wait for the remote to be available and connected,
|
|
41
|
+
otherwise return None if there is no Remote available yet.
|
|
70
42
|
"""
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
43
|
+
raise NotImplementedError(f"'get_remote' not implemented for {self.__class__.__name__}")
|
|
44
|
+
|
|
45
|
+
def start(self):
|
|
46
|
+
"""
|
|
47
|
+
Start the Provisioner instance, start any provisioning-related
|
|
48
|
+
processes that lead to systems being reserved.
|
|
49
|
+
"""
|
|
50
|
+
raise NotImplementedError(f"'start' not implemented for {self.__class__.__name__}")
|
|
51
|
+
|
|
52
|
+
def stop(self):
|
|
53
|
+
"""
|
|
54
|
+
Stop the Provisioner instance, freeing all reserved resources,
|
|
55
|
+
calling .release() on all Remote instances that were created.
|
|
56
|
+
"""
|
|
57
|
+
raise NotImplementedError(f"'stop' not implemented for {self.__class__.__name__}")
|
|
58
|
+
|
|
59
|
+
def stop_defer(self):
|
|
60
|
+
"""
|
|
61
|
+
Enable an external caller to stop the Provisioner instance,
|
|
62
|
+
deferring resource deallocation to the caller.
|
|
63
|
+
|
|
64
|
+
Return an iterable of argument-free thread-safe callables that can be
|
|
65
|
+
called, possibly in parallel, to free up resources.
|
|
66
|
+
Ie. a list of 200 .release() functions, to be called in a thread pool
|
|
67
|
+
by the user, speeding up cleanup.
|
|
68
|
+
"""
|
|
69
|
+
return (self.stop,)
|
|
70
|
+
|
|
71
|
+
def __enter__(self):
|
|
72
|
+
try:
|
|
73
|
+
self.start()
|
|
74
|
+
return self
|
|
75
|
+
except Exception:
|
|
76
|
+
self.stop()
|
|
77
|
+
raise
|
|
78
|
+
|
|
79
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
80
|
+
self.stop()
|
|
98
81
|
|
|
99
82
|
|
|
100
83
|
class Remote(_connection.Connection):
|
|
101
84
|
"""
|
|
102
85
|
Representation of a provisioned (reserved) remote system, providing
|
|
103
|
-
a Connection-like API in addition system management helpers.
|
|
86
|
+
a Connection-like API in addition to system management helpers.
|
|
104
87
|
|
|
105
|
-
An instance of Remote is typically prepared by a Provisioner and
|
|
106
|
-
|
|
107
|
-
for repeated reserve/release cycles, hence the lack
|
|
88
|
+
An instance of Remote is typically prepared by a Provisioner and lent out
|
|
89
|
+
for further use, to be .release()d by the user (if destroyed).
|
|
90
|
+
It is not meant for repeated reserve/release cycles, hence the lack
|
|
91
|
+
of .reserve().
|
|
108
92
|
|
|
109
93
|
Also note that Remote can be used via Context Manager, but does not
|
|
110
94
|
do automatic .release(), the manager only handles the built-in Connection.
|
|
@@ -114,27 +98,12 @@ class Remote(_connection.Connection):
|
|
|
114
98
|
with a callback, or a try/finally block.
|
|
115
99
|
"""
|
|
116
100
|
|
|
117
|
-
# TODO: pass platform as arg ?
|
|
118
|
-
#def __init__(self, platform, *args, **kwargs):
|
|
119
|
-
# """
|
|
120
|
-
# Initialize a new Remote instance based on a Connection instance.
|
|
121
|
-
# If extending __init__, always call 'super().__init__(conn)' at the top.
|
|
122
|
-
# """
|
|
123
|
-
# self.lock = _threading.RLock()
|
|
124
|
-
# self.platform = platform
|
|
125
|
-
|
|
126
101
|
def release(self):
|
|
127
102
|
"""
|
|
128
|
-
Release (de-provision) the remote resource
|
|
103
|
+
Release (de-provision) the remote resource.
|
|
129
104
|
"""
|
|
130
105
|
raise NotImplementedError(f"'release' not implemented for {self.__class__.__name__}")
|
|
131
106
|
|
|
132
|
-
def alive(self):
|
|
133
|
-
"""
|
|
134
|
-
Return True if the remote resource is still valid and reserved.
|
|
135
|
-
"""
|
|
136
|
-
raise NotImplementedError(f"'alive' not implemented for {self.__class__.__name__}")
|
|
137
|
-
|
|
138
107
|
|
|
139
108
|
_submodules = [
|
|
140
109
|
info.name for info in _pkgutil.iter_modules(__spec__.submodule_search_locations)
|
|
@@ -1,24 +1,2 @@
|
|
|
1
|
-
from
|
|
2
|
-
from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class LibvirtProvisioner(base.Provisioner):
|
|
6
|
-
number = 123
|
|
7
|
-
|
|
8
|
-
def reserve(self):
|
|
9
|
-
util.debug(f"reserving {self.number}")
|
|
10
|
-
|
|
11
|
-
# TODO: as simple attribute, to be guaranteed set when reserve() returns,
|
|
12
|
-
# can be overriden by a getter function if you need to keep track
|
|
13
|
-
# how many times it was accessed
|
|
14
|
-
def connection(self):
|
|
15
|
-
#return {"Hostname": "1.2.3.4", "User": "root", "IdentityFile": ...}
|
|
16
|
-
util.debug(f"returning ssh for {self.number}")
|
|
17
|
-
return ssh.SSHConn({"Hostname": "1.2.3.4", "User": "root"})
|
|
18
|
-
|
|
19
|
-
def release(self):
|
|
20
|
-
util.debug(f"releasing {self.number}")
|
|
21
|
-
|
|
22
|
-
def alive(self):
|
|
23
|
-
util.debug(f"always alive: {self.number}")
|
|
24
|
-
return True
|
|
1
|
+
from . import locking # noqa: F401
|
|
2
|
+
from .libvirt import LibvirtCloningProvisioner, LibvirtCloningRemote # noqa: F401
|