atex 0.8__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.
@@ -0,0 +1,158 @@
1
+ """
2
+ Provides a namedtuple-inspired frozen mapping-backed data structure.
3
+
4
+ class MyMap(NamedMapping):
5
+ pass
6
+
7
+ m = MyMap(a=123, b=456)
8
+
9
+ m["a"] # 123
10
+ m.a # 123
11
+ m["a"] = 9 # KeyError (is read-only)
12
+ m.a = 9 # AttributeError (is read-only)
13
+
14
+ Like namedtuple, you can specify required keys that always need to be given
15
+ to the constructor:
16
+
17
+ class MyMap(NamedMapping, required=("key1", "key2")):
18
+ pass
19
+
20
+ m = MyMap(a=123, b=456, key1=999) # KeyError (key2 not specified)
21
+
22
+ Similarly, you can specify defaults (for required or non-required keys),
23
+ as a dict, that are used if omitted from the constructor:
24
+
25
+ class MyMap(NamedMapping, defaults={"key": 678}):
26
+ pass
27
+
28
+ m = MyMap() # will have m.key == 678
29
+
30
+ A class instance can unpack via ** with the entirety of its mapping contents:
31
+
32
+ m = MyMap(key2=456)
33
+ both = {'key1': 123, **m} # contains both keys
34
+
35
+ You can also chain (append to) required / default values through inheritance:
36
+
37
+ class MyMap(NamedMapping, required=("key1",), defaults={"key2": 234}):
38
+ pass
39
+
40
+ class AnotherMap(MyMap, required=("key3",))
41
+ pass
42
+
43
+ m = AnotherMap() # KeyError (key1 and key3 are required)
44
+
45
+ isinstance(m, MyMap) # would be True
46
+
47
+ When instantiating, it is also possible to copy just the required keys from
48
+ another dict-like object (does not have to be a parent of the class):
49
+
50
+ class SmallMap(NamedMapping, required=("key1", "key2")):
51
+ pass
52
+
53
+ class BigMap(SmallMap, required=("key3", "key4")):
54
+ pass
55
+
56
+ b = BigMap(key1=123, key2=456, key3=789, key4=0)
57
+
58
+ s = SmallMap._from(b) # will copy just key1 and key2
59
+ s = SmallMap._from(b, extra=555) # can pass extra **kwargs to __init__
60
+ s = SmallMap(**b) # will copy all keys
61
+
62
+ Note that this is a fairly basic implementation without __hash__, etc.
63
+ """
64
+
65
+ import abc
66
+ import collections
67
+
68
+
69
+ class _NamedMappingMeta(abc.ABCMeta):
70
+ def __new__(
71
+ metacls, name, bases, namespace, *, required=None, default=None, **kwargs, # noqa: N804
72
+ ):
73
+ new_required = []
74
+ for base in bases:
75
+ new_required.extend(getattr(base, "_required", ()))
76
+ if required:
77
+ new_required.extend(required)
78
+ namespace["_required"] = tuple(set(new_required))
79
+
80
+ new_default = {}
81
+ for base in bases:
82
+ new_default.update(getattr(base, "_default", {}))
83
+ if default:
84
+ new_default.update(default)
85
+ namespace["_default"] = new_default
86
+
87
+ return super().__new__(metacls, name, bases, namespace, **kwargs)
88
+
89
+
90
+ class NamedMapping(collections.abc.Mapping, metaclass=_NamedMappingMeta):
91
+ __slots__ = ("_data",)
92
+
93
+ def __init__(self, **keys):
94
+ data = {}
95
+ if hasattr(self, "_default"):
96
+ data.update(self._default)
97
+ data.update(keys)
98
+ if hasattr(self, "_required"):
99
+ for key in self._required:
100
+ if key not in data:
101
+ raise KeyError(f"'{self.__class__.__name__}' requires key '{key}'")
102
+ object.__setattr__(self, "_data", data)
103
+
104
+ @classmethod
105
+ def _from(cls, foreign, **keys):
106
+ """
107
+ (keys is like for __init__)
108
+ """
109
+ foreign_data = {}
110
+ if hasattr(cls, "_required"):
111
+ for key in cls._required:
112
+ if key in foreign:
113
+ foreign_data[key] = foreign[key]
114
+ foreign_data.update(keys)
115
+ return cls(**foreign_data)
116
+
117
+ def __getattr__(self, item):
118
+ if item in ("_data", "_required", "_default"):
119
+ return super().__getattr__(item)
120
+ try:
121
+ return self._data[item]
122
+ except KeyError:
123
+ raise AttributeError(
124
+ f"'{self.__class__.__name__}' object has no attribute '{item}'",
125
+ name=item,
126
+ ) from None
127
+
128
+ def __setattr__(self, name, value):
129
+ raise AttributeError(
130
+ f"'{self}' is read-only, cannot set '{name}'",
131
+ name=name,
132
+ obj=value,
133
+ )
134
+
135
+ def __getitem__(self, key):
136
+ return self._data[key]
137
+
138
+ def __setitem__(self, key, value):
139
+ raise ValueError(f"'{self}' is read-only, cannot set '{key}'")
140
+
141
+ def __delitem__(self, key):
142
+ raise ValueError(f"'{self}' is read-only, cannot delete '{key}'")
143
+
144
+ def __contains__(self, key):
145
+ return key in self._data
146
+
147
+ def __iter__(self):
148
+ return iter(self._data)
149
+
150
+ def __len__(self):
151
+ return len(self._data)
152
+
153
+ def __repr__(self):
154
+ return (
155
+ f"{self.__class__.__name__}("
156
+ + ", ".join((f"{k}={repr(v)}" for k,v in self._data.items()))
157
+ + ")"
158
+ )
atex/util/threads.py CHANGED
@@ -1,48 +1,85 @@
1
- import collections
2
1
  import queue
3
2
  import threading
4
3
 
4
+ from .named_mapping import NamedMapping
5
+
5
6
  # TODO: documentation; this is like concurrent.futures, but with daemon=True support
6
7
 
7
8
 
8
9
  class ThreadQueue:
9
- ThreadReturn = collections.namedtuple("ThreadReturn", ("thread", "returned", "exception"))
10
+ class ThreadReturn(NamedMapping, required=("thread", "returned", "exception")):
11
+ pass
12
+
10
13
  Empty = queue.Empty
11
14
 
12
15
  def __init__(self, daemon=False):
16
+ self.lock = threading.RLock()
13
17
  self.queue = queue.SimpleQueue()
14
18
  self.daemon = daemon
15
19
  self.threads = set()
16
20
 
17
- def _wrapper(self, func, *args, **kwargs):
21
+ def _wrapper(self, func, func_args, func_kwargs, **user_kwargs):
18
22
  current_thread = threading.current_thread()
19
23
  try:
20
- ret = func(*args, **kwargs)
21
- result = self.ThreadReturn(current_thread, ret, None)
24
+ ret = func(*func_args, **func_kwargs)
25
+ result = self.ThreadReturn(
26
+ thread=current_thread,
27
+ returned=ret,
28
+ exception=None,
29
+ **user_kwargs,
30
+ )
22
31
  except Exception as e:
23
- result = self.ThreadReturn(current_thread, None, e)
32
+ result = self.ThreadReturn(
33
+ thread=current_thread,
34
+ returned=None,
35
+ exception=e,
36
+ **user_kwargs,
37
+ )
24
38
  self.queue.put(result)
25
39
 
26
- def start_thread(self, target, name=None, args=None, kwargs=None):
27
- args = args or ()
28
- kwargs = kwargs or {}
40
+ def start_thread(self, target, target_args=None, target_kwargs=None, **user_kwargs):
41
+ """
42
+ Start a new thread and call 'target' as a callable inside it, passing it
43
+ 'target_args' as arguments and 'target_kwargs' as keyword arguments.
44
+
45
+ Any additional 'user_kwargs' specified are NOT passed to the callable,
46
+ but instead become part of the ThreadReturn namespace returned by the
47
+ .get_raw() method.
48
+ """
29
49
  t = threading.Thread(
30
50
  target=self._wrapper,
31
- name=name,
32
- args=(target, *args),
33
- kwargs=kwargs,
51
+ args=(target, target_args or (), target_kwargs or {}),
52
+ kwargs=user_kwargs,
34
53
  daemon=self.daemon,
35
54
  )
55
+ with self.lock:
56
+ self.threads.add(t)
36
57
  t.start()
37
- self.threads.add(t)
58
+
59
+ def get_raw(self, block=True, timeout=None):
60
+ """
61
+ Wait for and return the next available ThreadReturn instance on the
62
+ queue, as enqueued by a finished callable started by the .start_thread()
63
+ method.
64
+ """
65
+ with self.lock:
66
+ if block and timeout is None and not self.threads:
67
+ raise AssertionError("no threads are running, would block forever")
68
+ treturn = self.queue.get(block=block, timeout=timeout)
69
+ with self.lock:
70
+ self.threads.remove(treturn.thread)
71
+ return treturn
38
72
 
39
73
  # get one return value from any thread's function, like .as_completed()
40
74
  # or concurrent.futures.FIRST_COMPLETED
41
75
  def get(self, block=True, timeout=None):
42
- if block and timeout is None and not self.threads:
43
- raise AssertionError("no threads are running, would block forever")
44
- treturn = self.queue.get(block=block, timeout=timeout)
45
- self.threads.remove(treturn.thread)
76
+ """
77
+ Wait for and return the next available return value of a callable
78
+ enqueued via the .start_thread() method.
79
+
80
+ If the callable raised an exception, the exception is re-raised here.
81
+ """
82
+ treturn = self.get_raw(block, timeout)
46
83
  if treturn.exception is not None:
47
84
  raise treturn.exception
48
85
  else:
@@ -50,6 +87,13 @@ class ThreadQueue:
50
87
 
51
88
  # wait for all threads to finish (ignoring queue contents)
52
89
  def join(self):
53
- while self.threads:
54
- t = self.threads.pop()
55
- t.join()
90
+ """
91
+ Wait for all threads to finish, ignoring the state of the queue.
92
+ """
93
+ while True:
94
+ with self.lock:
95
+ try:
96
+ thread = self.threads.pop()
97
+ except KeyError:
98
+ break
99
+ thread.join()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: atex
3
- Version: 0.8
3
+ Version: 0.9
4
4
  Summary: Ad-hoc Test EXecutor
5
5
  Project-URL: Homepage, https://github.com/RHSecurityCompliance/atex
6
6
  License-Expression: GPL-3.0-or-later
@@ -10,6 +10,7 @@ Classifier: Programming Language :: Python :: 3
10
10
  Classifier: Topic :: Software Development :: Testing
11
11
  Requires-Python: >=3.11
12
12
  Requires-Dist: fmf>=1.6
13
+ Requires-Dist: pyyaml
13
14
  Requires-Dist: urllib3<3,>=2
14
15
  Description-Content-Type: text/markdown
15
16
 
@@ -45,6 +46,30 @@ BREAK. DO NOT USE IT (for now).
45
46
  Unless specified otherwise, any content within this repository is distributed
46
47
  under the GNU GPLv3 license, see the [COPYING.txt](COPYING.txt) file for more.
47
48
 
49
+ ## Testing this project
50
+
51
+ There are some limited sanity tests provided via `pytest`, although:
52
+
53
+ * Some require additional variables (ie. Testing Farm) and will ERROR
54
+ without them.
55
+ * Some take a long time (ie. Testing Farm) due to system provisioning
56
+ taking a long time, so install `pytest-xdist` and run with a large `-n`.
57
+
58
+ Currently, the recommended approach is to split the execution:
59
+
60
+ ```
61
+ # synchronously, because podman CLI has concurrency issues
62
+ pytest tests/provision/test_podman.py
63
+
64
+ # in parallel, because provisioning takes a long time
65
+ export TESTING_FARM_API_TOKEN=...
66
+ export TESTING_FARM_COMPOSE=...
67
+ pytest -n 20 tests/provision/test_podman.py
68
+
69
+ # fast enough for synchronous execution
70
+ pytest tests/fmf
71
+ ```
72
+
48
73
  ## Parallelism and cleanup
49
74
 
50
75
  There are effectively 3 methods of running things in parallel in Python:
@@ -149,49 +174,5 @@ TODO: codestyle from contest
149
174
  - the whole point is to make usecase-targeted easy-to-use tools that don't
150
175
  intimidate users with 1 KB long command line, and runcontest is a nice example
151
176
 
152
- - TL;DR - use a modular pythonic approach, not a modular CLI like tmt
153
-
154
-
155
- - Orchestrator with
156
- - add_provisioner(<class>, max_workers=1) # will instantiate <class> at most max_workers at a time
157
- - algo
158
- - for all provisioner classes, spawns classes*max_workers as new Threads
159
- - waits for any .reserve() to return
160
- - creates a new Thread for minitmt, gives it p.get_ssh() details
161
- - minitmt will
162
- - establish a SSHConn
163
- - install test deps, copy test repo over, prepare socket dir on SUT, etc.
164
- - run the test in the background as
165
- f=os.open('some/test/log', os.WRONLY); subprocess.Popen(..., stdout=f, stderr=f, stdin=subprocess.DEVNULL)
166
- - read/process Unix sock results in the foreground, non-blocking,
167
- probably calling some Orchestrator-provided function to store results persistently
168
- - regularly check Popen proc status, re-accept UNIX sock connection, etc., etc.
169
- - minitmt also has some Thread-independent way to .cancel(), killing the proc, closing SSHConn, etc.
170
-
171
- - while waiting for minitmt Threads to finish, to re-assign existing Provisioner instances
172
- to new minitmt Threads, .. Orchestrator uses some logic to select, which TestRun
173
- would be ideal to run next
174
- - TestRun probably has some "fitness" function that returns some priority number
175
- when given a Provisioner instance (?) ...
176
- - something from minitmt would also have access to the Provisioner instance
177
- - the idea is to allow some logic to set "hey I set up nested VM snapshot on this thing"
178
- on the Provisioner instance, and if another /hardening/oscap TestRun finds
179
- a Provisioner instance like that, it would return high priority
180
- - ...
181
- - similar to "fitness" like function, we need some "applicability" function
182
- - if TestRun is mixed to RHEL-9 && x86_64, we need it to return True
183
- for a Provisioner instance that provides RHEL-9 and x86_64, but False otherwise
184
-
185
- - basically Orchestrator has
186
- - .add_provisioner()
187
- - .run_test() # called with an exclusively-borrowed Provisioner instance
188
- - if Provisioner is_alive()==False after .run_test(), instantiate a new one from the same inst.__class__
189
- - if test failed and reruns > 0, try run_test() again (or maybe re-queue the test)
190
- - .output_result() # called by run_test() to persistently log a test result
191
- - .applicable() # return True if a passed TestRun is meant for a passed Platform (Provisioner?)
192
- - if no TestRun returns True, the Provisioner is .release()d because we don't need it anymore
193
- - .fitness() # return -inf / 0 / +inf with how much should a passed TestRun run on a Provisioner
194
- - MAYBE combine applicable() and fitness() into one function, next_test() ?
195
- - given the free Provisioner and a list of TestRuns, select which should run next on the Provisioner
196
- - if none is chosen, .release() the Provisioner without replacement, continue
177
+ - TL;DR - use a modular pythonic approach, not a gluetool-style long CLI
197
178
  ```
@@ -0,0 +1,43 @@
1
+ atex/__init__.py,sha256=LdX67gprtHYeAkjLhFPKzpc7ECv2rHxUbHKDGbGXO1c,517
2
+ atex/fmf.py,sha256=gkJXIaRO7_KvwJR-V6Tc1NVn4a9Hq7hoBLQLhxYIdbg,8834
3
+ atex/cli/__init__.py,sha256=erHv68SsybRbdgJ60013y9jVqY1ec-cb9T9ThPCJ_HY,2408
4
+ atex/cli/fmf.py,sha256=HfbTgFbCwK4Nuyq6vtGutcq_4-4kj-tmoqzXUn3AYtY,3573
5
+ atex/cli/libvirt.py,sha256=vGcan9u0Nor_DaEjgOj3Yzjtlq4WNVLr5oYMb8zFb6M,3743
6
+ atex/cli/testingfarm.py,sha256=DHMupwU3AjbkwkzvzdhlxtsuBnxVaba5i8T8g9sKRug,7569
7
+ atex/connection/__init__.py,sha256=dj8ZBcEspom7Z_UjecfLGBRNvLZ3dyGR9q19i_B4xpY,3880
8
+ atex/connection/podman.py,sha256=JUsi4jOkNFGsEHCqUQF003R2yRfJPsMnUSBEZM3H3Kk,1953
9
+ atex/connection/ssh.py,sha256=c8v01mj0pf6VU8z2cLLCvPGPmGUZp8wQsTG441k3Qy4,13674
10
+ atex/executor/__init__.py,sha256=XCfhi7QDELjey7N1uzhMjc46Kp1Jsd5bOCf52I27SCE,85
11
+ atex/executor/duration.py,sha256=x06sItKOZi6XA8KszQwZGpIb1Z_L-HWqIwZKo2SDo0s,1759
12
+ atex/executor/executor.py,sha256=OcKBXQ77OktmzPWAbdCb81Yj44Jr4SEkwW_CxdEhFP4,15674
13
+ atex/executor/reporter.py,sha256=MceFmHFt0bTEClBZbRI1WnFbfMhR0e1noOzcu7gjKuQ,3403
14
+ atex/executor/scripts.py,sha256=6xqP-m_9UCVb3z0tCWIMczimz_cTeCIJucSp0AGYsRw,5567
15
+ atex/executor/testcontrol.py,sha256=O4V4jRx7lZv-El1i9jkPha-aWzjq_8m6loK7sNGVD14,12695
16
+ atex/orchestrator/__init__.py,sha256=GSHtWoZjJrLiatjUHsMAkYB8VebSQD9ApQw0ymCrGTQ,212
17
+ atex/orchestrator/aggregator.py,sha256=naypN8T42iPau_4eLeXak-INR1_vsYhP_QSp3xLM_FA,3837
18
+ atex/orchestrator/orchestrator.py,sha256=qAwka7MqpAWA6mLgsMl1m1HpQP2mERcaAASNvJwgfTM,14570
19
+ atex/provision/__init__.py,sha256=Pj_JnDaJA8DzKRGmLcc2JiwPsuQc2TYlE-hDR56SwTY,4083
20
+ atex/provision/libvirt/VM_PROVISION,sha256=7pkZ-ozgTyK4qNGC-E-HUznr4IhbosWSASbB72Gknl8,2664
21
+ atex/provision/libvirt/__init__.py,sha256=pKG5IpZSC2IHs5wL2ecQx_fd9AzAXEbZmDzA7RyZsfM,119
22
+ atex/provision/libvirt/libvirt.py,sha256=7wux-zhQoNODJoPB4iMqPlGEJe7rEEZeLSOtMU3TB0M,18160
23
+ atex/provision/libvirt/locking.py,sha256=e9zbtR0uzJZBAzucfhs9VQaDCx-jp0pWJi1pb7JPK4w,5630
24
+ atex/provision/libvirt/setup-libvirt.sh,sha256=oCMy9SCnbC_QuAzO2sFwvB5ui1kMQ6uviHsgdXyoFXc,2428
25
+ atex/provision/podman/__init__.py,sha256=V9miIDQV-CyDVcbf2-1qtDbXDhhZzJza5oXas-JxI8o,66
26
+ atex/provision/podman/podman.py,sha256=FJK4uLDuHBj8_3Wlg4a-4JgGIRGyLX4v7UVcxEorHbA,9578
27
+ atex/provision/testingfarm/__init__.py,sha256=kZncgLGdRCR4FMaRQr2GTwJ8vjlA-24ri8JO2ueZJuw,113
28
+ atex/provision/testingfarm/api.py,sha256=9xeoIN28KumJyMUEUoyEUZcIxVH9G34Wecyy3bp2Cmg,21612
29
+ atex/provision/testingfarm/testingfarm.py,sha256=-Q33FAretSGPWdmNJUywJZVfXYGtsAfLP5uqRZTGfQQ,8631
30
+ atex/util/__init__.py,sha256=cWHFbtQ4mDlKe6lXyPDWRmWJOTcHDGfVuW_-GYa8hB0,1473
31
+ atex/util/dedent.py,sha256=SEuJMtLzqz3dQ7g7qyZzEJ9VYynVlk52tQCJY-FveXo,603
32
+ atex/util/libvirt.py,sha256=kDZmT6xLYEZkQNLZY98gJ2M48DDWXxHF8rQY9PnjB3U,660
33
+ atex/util/log.py,sha256=70f6YiF2RwNUfE5BXZMSQonzfI_uxQoD7_S4bRD_Btw,2466
34
+ atex/util/named_mapping.py,sha256=UBMe9TetjV-DGPhjYjJ42YtC40FVPKAAEROXl9MA5fo,4700
35
+ atex/util/path.py,sha256=x-kXqiWCVodfZWbEwtC5A8LFvutpDIPYv2m0boZSlXU,504
36
+ atex/util/ssh_keygen.py,sha256=9yuSl2yBV7pG3Qfsf9tossVC00nbIUrAeLdbwTykpjk,384
37
+ atex/util/subprocess.py,sha256=IQT9QHe2kMaaO_XPSry-DwObYstGsq6_QdwdbhYDjko,1826
38
+ atex/util/threads.py,sha256=46-5nV-qJqi1YZ4qEshmZXGUxr8j9_9xT9eEpkjRr5I,3355
39
+ atex-0.9.dist-info/METADATA,sha256=iLGFHVxeK9KWrPaRdL4hkbNkb-OgJkeohHhxYz90tAI,6857
40
+ atex-0.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
41
+ atex-0.9.dist-info/entry_points.txt,sha256=pLqJdcfeyQTgup2h6dWb6SvkHhtOl-W5Eg9zV8moK0o,39
42
+ atex-0.9.dist-info/licenses/COPYING.txt,sha256=oEuj51jdmbXcCUy7pZ-KE0BNcJTR1okudRp5zQ0yWnU,670
43
+ atex-0.9.dist-info/RECORD,,
@@ -1,59 +0,0 @@
1
-
2
- making a podman image from the currently installed OS:
3
-
4
- 1) dnf install into a separate installroot
5
-
6
- dnf
7
- --installroot=$INSTALLROOT \
8
- --setopt=install_weak_deps=False \
9
- --setopt=tsflags=nodocs \
10
- -y groupinstall minimal-environment
11
-
12
- as root (doesn't work well with unshare, maybe could work via bwrap (bubblewrap))
13
-
14
- maybe the unprivileged solution is pulling image from hub + installing @minimal-environment
15
- into it (perhaps via podman build)
16
-
17
-
18
- 2) post process it
19
-
20
- echo -n > "$INSTALLROOT/etc/machine-id"
21
- echo container > "$INSTALLROOT/etc/hostname"
22
-
23
- rm -rf "$INSTALLROOT/etc/yum.repos.d"
24
- cp -f /etc/yum.repos.d/* "$INSTALLROOT/etc/yum.repos.d/."
25
- cp -f /etc/pki/rpm-gpg/* "$INSTALLROOT/etc/pki/rpm-gpg/."
26
-
27
- echo install_weak_deps=False >> "$INSTALLROOT/etc/dnf/dnf.conf"
28
- echo tsflags=nodocs >> "$INSTALLROOT/etc/dnf/dnf.conf"
29
-
30
- ln -sf \
31
- /usr/lib/systemd/system/multi-user.target \
32
- "$INSTALLROOT/etc/systemd/system/default.target"
33
-
34
- # disable auditd
35
- # disable other services
36
- # set root password
37
-
38
- dnf clean all --installroot="$INSTALLROOT"
39
-
40
-
41
- 3) pack it
42
-
43
- tar --xattrs -C "$INSTALLROOT" -cvf tarball.tar .
44
-
45
- rm -rf "$INSTALLROOT"
46
-
47
-
48
- 4) import it to podman
49
-
50
- podman import --change 'CMD ["/sbin/init"]' tarball.tar my-image-name
51
-
52
-
53
- 5) run it
54
-
55
- podman {run,create} --systemd=always --cgroups=split ...
56
-
57
-
58
-
59
- ------------------------------
@@ -1,74 +0,0 @@
1
- #!/bin/bash
2
-
3
- if [[ $# -lt 1 ]]; then
4
- echo "usage: $0 <podman-image-name>" >&2
5
- exit 1
6
- fi
7
- image_name="$1"
8
-
9
- set -e -x
10
-
11
- tmpdir=$(mktemp -d -p /var/tmp)
12
- trap "rm -rf '$tmpdir'" EXIT
13
-
14
- installroot="$tmpdir/root"
15
-
16
- dnf \
17
- --installroot="$installroot" \
18
- --setopt=install_weak_deps=False \
19
- --setopt=tsflags=nodocs \
20
- -q -y groupinstall minimal-environment
21
-
22
- echo -n > "$installroot/etc/machine-id"
23
- #echo container > "$installroot/etc/hostname"
24
-
25
- cp -f /etc/yum.repos.d/* "$installroot/etc/yum.repos.d/."
26
- cp -f /etc/pki/rpm-gpg/* "$installroot/etc/pki/rpm-gpg/."
27
-
28
- echo install_weak_deps=False >> "$installroot/etc/dnf/dnf.conf"
29
- echo tsflags=nodocs >> "$installroot/etc/dnf/dnf.conf"
30
-
31
- ln -sf \
32
- /usr/lib/systemd/system/multi-user.target \
33
- "$installroot/etc/systemd/system/default.target"
34
-
35
- systemctl --root="$installroot" disable \
36
- auditd.service crond.service rhsmcertd.service sshd.service
37
-
38
- #encrypted=$(openssl passwd -6 somepass)
39
- #usermod --root="$installroot" --password "$encrypted" root
40
-
41
- dnf clean packages --installroot="$installroot"
42
-
43
- tar --xattrs -C "$installroot" -cf "$tmpdir/packed.tar" .
44
-
45
- rm -rf "$installroot"
46
-
47
- podman import \
48
- --change 'CMD ["/sbin/init"]' \
49
- "$tmpdir/packed.tar" "$image_name"
50
-
51
- # start as
52
- # podmn {run,create} --systemd=always --cgroups=split --device /dev/kvm ...
53
- #
54
- # podman run -t -i \
55
- # --systemd=always --cgroups=split \
56
- # --device /dev/kvm \
57
- # --network=bridge \
58
- # --cap-add NET_ADMIN --cap-add NET_RAW --cap-add SYS_MODULE \
59
- # --mount type=bind,src=/lib/modules,dst=/lib/modules,ro \
60
- # --mount type=bind,src=/proc/sys/net,dst=/proc/sys/net,rw \
61
- # my_container
62
- #
63
- # as unprivileged user:
64
- # podman run -t -i \
65
- # --systemd=always --cgroups=split --network=bridge --privileged \
66
- # my_container
67
- #
68
- # container setup:
69
- # dnf -y install libvirt-daemon qemu-kvm libvirt-client libvirt-daemon-driver-qemu virt-install libvirt-daemon-driver-storage libvirt-daemon-config-network
70
- # echo $'user = "root"\ngroup = "root"\nremember_owner = 0' >> /etc/libvirt/qemu.conf
71
- # systemctl start virtqemud.socket virtstoraged.socket virtnetworkd.socket
72
- # virsh net-start default
73
- # virt-install --install fedora40 --disk /var/lib/libvirt/images/foo.qcow2,size=20 --console pty --check disk_size=off --unattended --graphics none
74
-
atex-0.8.dist-info/RECORD DELETED
@@ -1,37 +0,0 @@
1
- atex/__init__.py,sha256=LdX67gprtHYeAkjLhFPKzpc7ECv2rHxUbHKDGbGXO1c,517
2
- atex/fmf.py,sha256=ofbrJx2362qHAxERS-WulK4TMpbp0C4HQ-Js917Ll9w,7871
3
- atex/cli/__init__.py,sha256=erHv68SsybRbdgJ60013y9jVqY1ec-cb9T9ThPCJ_HY,2408
4
- atex/cli/fmf.py,sha256=5DbA-3rfbFZ41fJ5z7Tiz5FmuZhXNC7gRAQfIGX7pXc,2516
5
- atex/cli/testingfarm.py,sha256=wdN26TE9jZ0ozet-JBQQgIcRi0WIV3u_i-7_YYi_SUg,7248
6
- atex/connection/__init__.py,sha256=xFwGOvlFez1lIt1AD6WXgEEIbsF22pSpQFv41GEAGAI,3798
7
- atex/connection/ssh.py,sha256=vrrSfVdQoz5kWiZbiPuM8KGneMl2Tlb0VeJIHTFSSYs,13626
8
- atex/executor/__init__.py,sha256=XCfhi7QDELjey7N1uzhMjc46Kp1Jsd5bOCf52I27SCE,85
9
- atex/executor/duration.py,sha256=x06sItKOZi6XA8KszQwZGpIb1Z_L-HWqIwZKo2SDo0s,1759
10
- atex/executor/executor.py,sha256=QYYSlEfBZIm95NhM1gwd2ROeshSAavYu2DP_4TTHlQs,14770
11
- atex/executor/reporter.py,sha256=nW_Uls3R4Ev80a2ZNJl3nxAYrcYhXk5Cy9nAUMlYPrc,3326
12
- atex/executor/scripts.py,sha256=yE4Lbfu-TPkBcB5t15-t-tF79H8pBJWbWP6MKRSvKsw,5356
13
- atex/executor/testcontrol.py,sha256=-rfihfE6kryIGurFrHBPSS8ANaIJkzX-zfpOO8To-9o,12204
14
- atex/orchestrator/__init__.py,sha256=eF-6ix5rFEu85fBFzgSdTYau7bNTkIQndAU7QqeI-FA,105
15
- atex/orchestrator/aggregator.py,sha256=5-8nHVeW6kwImoEYOsQqsx6UBdbKc5xuj6qlg7dtOF8,3642
16
- atex/orchestrator/orchestrator.py,sha256=tQu_d8_9y3rOLHskb694NJKNvxplQWAZ2R452Sy3AXw,12056
17
- atex/provision/__init__.py,sha256=2d_hRVPxXF5BVbQ_Gn1OR-F2xuqRn8O0yyVbvSrtTIg,4043
18
- atex/provision/libvirt/VM_PROVISION,sha256=7pkZ-ozgTyK4qNGC-E-HUznr4IhbosWSASbB72Gknl8,2664
19
- atex/provision/libvirt/__init__.py,sha256=mAkGtciZsXdR9MVVrjm3OWNXZqTs_33-J1qAszFA0k4,768
20
- atex/provision/libvirt/setup-libvirt.sh,sha256=CXrEFdrj8CSHXQZCd2RWuRvTmw7QYFTVhZeLuhhXooI,1855
21
- atex/provision/podman/README,sha256=kgP3vcTfWW9gcQzmXnyucjgWbqjNqm_ZM--pnqNTXRg,1345
22
- atex/provision/podman/host_container.sh,sha256=buCNz0BlsHY5I64sMSTGQHkvzEK0aeIhpGJXWCQVMXk,2283
23
- atex/provision/testingfarm/__init__.py,sha256=kZncgLGdRCR4FMaRQr2GTwJ8vjlA-24ri8JO2ueZJuw,113
24
- atex/provision/testingfarm/api.py,sha256=jiEJhYxMTzRihayceHcnDnGKNZJisYWn2o_TAdCI2Xo,19943
25
- atex/provision/testingfarm/testingfarm.py,sha256=wp8W3bwOmQdO-UUOdqu_JLtOZTGaNg-wERFfLySwZmI,8587
26
- atex/util/__init__.py,sha256=cWHFbtQ4mDlKe6lXyPDWRmWJOTcHDGfVuW_-GYa8hB0,1473
27
- atex/util/dedent.py,sha256=SEuJMtLzqz3dQ7g7qyZzEJ9VYynVlk52tQCJY-FveXo,603
28
- atex/util/log.py,sha256=KZkuw4jl8YTUOHZ4wNBrfDeg16VpLa82-IZYFHfqwgk,1995
29
- atex/util/path.py,sha256=x-kXqiWCVodfZWbEwtC5A8LFvutpDIPYv2m0boZSlXU,504
30
- atex/util/ssh_keygen.py,sha256=9yuSl2yBV7pG3Qfsf9tossVC00nbIUrAeLdbwTykpjk,384
31
- atex/util/subprocess.py,sha256=IQT9QHe2kMaaO_XPSry-DwObYstGsq6_QdwdbhYDjko,1826
32
- atex/util/threads.py,sha256=bezDIEIMcQinmG7f5E2K6_mHJQOlwx7W3I9CKkCYAYA,1830
33
- atex-0.8.dist-info/METADATA,sha256=dvXW146ZvIfyzqPqGbKmhTNScLTZM7C5K0FLrGNGIJ0,8981
34
- atex-0.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
35
- atex-0.8.dist-info/entry_points.txt,sha256=pLqJdcfeyQTgup2h6dWb6SvkHhtOl-W5Eg9zV8moK0o,39
36
- atex-0.8.dist-info/licenses/COPYING.txt,sha256=oEuj51jdmbXcCUy7pZ-KE0BNcJTR1okudRp5zQ0yWnU,670
37
- atex-0.8.dist-info/RECORD,,
File without changes