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.
Files changed (48) hide show
  1. atex/cli/fmf.py +143 -0
  2. atex/cli/libvirt.py +127 -0
  3. atex/cli/testingfarm.py +35 -13
  4. atex/connection/__init__.py +13 -19
  5. atex/connection/podman.py +63 -0
  6. atex/connection/ssh.py +34 -52
  7. atex/executor/__init__.py +2 -0
  8. atex/executor/duration.py +60 -0
  9. atex/executor/executor.py +402 -0
  10. atex/executor/reporter.py +101 -0
  11. atex/{minitmt → executor}/scripts.py +37 -25
  12. atex/{minitmt → executor}/testcontrol.py +54 -42
  13. atex/fmf.py +237 -0
  14. atex/orchestrator/__init__.py +3 -59
  15. atex/orchestrator/aggregator.py +82 -134
  16. atex/orchestrator/orchestrator.py +385 -0
  17. atex/provision/__init__.py +74 -105
  18. atex/provision/libvirt/__init__.py +2 -24
  19. atex/provision/libvirt/libvirt.py +465 -0
  20. atex/provision/libvirt/locking.py +168 -0
  21. atex/provision/libvirt/setup-libvirt.sh +21 -1
  22. atex/provision/podman/__init__.py +1 -0
  23. atex/provision/podman/podman.py +274 -0
  24. atex/provision/testingfarm/__init__.py +2 -29
  25. atex/provision/testingfarm/api.py +123 -65
  26. atex/provision/testingfarm/testingfarm.py +234 -0
  27. atex/util/__init__.py +1 -6
  28. atex/util/libvirt.py +18 -0
  29. atex/util/log.py +31 -8
  30. atex/util/named_mapping.py +158 -0
  31. atex/util/path.py +16 -0
  32. atex/util/ssh_keygen.py +14 -0
  33. atex/util/threads.py +99 -0
  34. atex-0.9.dist-info/METADATA +178 -0
  35. atex-0.9.dist-info/RECORD +43 -0
  36. atex/cli/minitmt.py +0 -175
  37. atex/minitmt/__init__.py +0 -23
  38. atex/minitmt/executor.py +0 -348
  39. atex/minitmt/fmf.py +0 -202
  40. atex/provision/nspawn/README +0 -74
  41. atex/provision/podman/README +0 -59
  42. atex/provision/podman/host_container.sh +0 -74
  43. atex/provision/testingfarm/foo.py +0 -1
  44. atex-0.7.dist-info/METADATA +0 -102
  45. atex-0.7.dist-info/RECORD +0 -32
  46. {atex-0.7.dist-info → atex-0.9.dist-info}/WHEEL +0 -0
  47. {atex-0.7.dist-info → atex-0.9.dist-info}/entry_points.txt +0 -0
  48. {atex-0.7.dist-info → atex-0.9.dist-info}/licenses/COPYING.txt +0 -0
@@ -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
- Any class derived from Provisioner serves as a mechanisms for requesting
13
- a resource (machine/system), waiting for it to be reserved, providing ssh
14
- details on how to connect to it, and releasing it when no longer useful.
15
-
16
- The 4 main API points for this are reserve(), connection(), release() and
17
- alive().
18
- If necessary, these methods can share data via class instance attributes,
19
- which are transparently guarded by a thread-aware mutex. For any complex
20
- reads/writes, use 'self.lock' via a context manager.
21
-
22
- Note that reserve() always runs in a separate thread (and thus may block),
23
- and other functions (incl. release()) may be called at any time from
24
- a different thread, even while reserve() is still running.
25
- It is thus recommended for reserve() to store metadata in self.* as soon
26
- as the metadata becomes available (some job ID, request UUID, Popen proc
27
- object with PID, etc.) so that release() can free the resource at any time.
28
-
29
- Once release()'d, the instance is never reused for reserve() again.
30
- However connection(), release() and alive() may be called several times at
31
- any time and need to handle it safely.
32
- Ie. once released(), an instance must never return alive() == True.
33
-
34
- # explicit method calls
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 __init__(self):
36
+ def get_remote(self, block=True):
67
37
  """
68
- Initialize the provisioner instance.
69
- If extending __init__, always call 'super().__init__()' at the top.
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
- self.lock = _threading.RLock()
72
-
73
- # def reserve(self):
74
- # """
75
- # Send a reservation request for a resource and wait for it to be
76
- # reserved.
77
- # """
78
- # raise NotImplementedError(f"'reserve' not implemented for {self.__class__.__name__}")
79
- #
80
- # def connection(self):
81
- # """
82
- # Return an atex.ssh.SSHConn instance configured for connection to
83
- # the reserved resource, but not yet connected.
84
- # """
85
- # raise NotImplementedError(f"'connection' not implemented for {self.__class__.__name__}")
86
- #
87
- # def release(self):
88
- # """
89
- # Release a reserved resource, or cancel a reservation-in-progress.
90
- # """
91
- # raise NotImplementedError(f"'release' not implemented for {self.__class__.__name__}")
92
- #
93
- # def alive(self):
94
- # """
95
- # Return True if the resource is still reserved, False otherwise.
96
- # """
97
- # raise NotImplementedError(f"'alive' not implemented for {self.__class__.__name__}")
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 given
106
- away for further use, to be .release()d by the user. It is not meant
107
- for repeated reserve/release cycles, hence the lack of .reserve().
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, freeing resources.
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 .. import base
2
- from ... import util, ssh
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