testcloud 0.11.6__tar.gz → 0.11.7__tar.gz
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.
- {testcloud-0.11.6/testcloud.egg-info → testcloud-0.11.7}/PKG-INFO +1 -1
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/conf.py +1 -1
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/__init__.py +1 -1
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/cli.py +1 -1
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/config.py +4 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/domain_configuration.py +19 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/instance.py +38 -2
- {testcloud-0.11.6 → testcloud-0.11.7/testcloud.egg-info}/PKG-INFO +1 -1
- {testcloud-0.11.6 → testcloud-0.11.7}/.gitignore +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/LICENSE +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/README.md +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/conf/99-testcloud-nonroot-libvirt-access.rules +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/conf/settings-example.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/conf/testcloud +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/LICENSE +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/Makefile +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/api.rst +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/indepth.rst +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/index.rst +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/manpages/testcloud.1 +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/pyproject.toml +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/requirements.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/run_testcloud.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/setup.cfg +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/setup.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/test/__init__.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/test/test_cli.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/test/test_config.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/test/test_image.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/test/test_instance.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/__init__.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/alma.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/centos.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/debian.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/fedora.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/misc.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/oracle.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/rocky.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/ubuntu.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/exceptions.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/image.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/sql.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/util.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/workarounds.py +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/SOURCES.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/dependency_links.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/entry_points.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/requires.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/top_level.txt +0 -0
- {testcloud-0.11.6 → testcloud-0.11.7}/tox.ini +0 -0
|
@@ -100,6 +100,10 @@ class ConfigData(object):
|
|
|
100
100
|
|
|
101
101
|
__DATA_DIR = "/var/lib/testcloud"
|
|
102
102
|
|
|
103
|
+
# This must point to location where virtlogd is
|
|
104
|
+
# permitted by SELinux to search
|
|
105
|
+
CONSOLE_LOG_DIR = "/var/lib/testcloud"
|
|
106
|
+
|
|
103
107
|
@property
|
|
104
108
|
def DATA_DIR(self):
|
|
105
109
|
return self.__DATA_DIR
|
|
@@ -4,12 +4,16 @@ import xml.dom.minidom
|
|
|
4
4
|
import os
|
|
5
5
|
import uuid
|
|
6
6
|
import platform
|
|
7
|
+
import subprocess
|
|
8
|
+
import logging
|
|
7
9
|
|
|
8
10
|
from testcloud.exceptions import TestcloudInstanceError
|
|
9
11
|
from testcloud import config
|
|
10
12
|
from testcloud import util
|
|
11
13
|
from testcloud import image
|
|
12
14
|
|
|
15
|
+
log = logging.getLogger("testcloud.domain_configuration")
|
|
16
|
+
|
|
13
17
|
config_data = config.get_config()
|
|
14
18
|
|
|
15
19
|
|
|
@@ -311,6 +315,8 @@ class IOMMUConfiguration:
|
|
|
311
315
|
model=self.model
|
|
312
316
|
)
|
|
313
317
|
|
|
318
|
+
def get_console_log_real_path(instance_uuid: str, suffix="console.log"):
|
|
319
|
+
return os.path.join(config_data.CONSOLE_LOG_DIR, f"{instance_uuid}-{suffix}")
|
|
314
320
|
|
|
315
321
|
class DomainConfiguration:
|
|
316
322
|
name: str
|
|
@@ -325,6 +331,7 @@ class DomainConfiguration:
|
|
|
325
331
|
qemu_args: list[str]
|
|
326
332
|
qemu_envs: dict[str, str]
|
|
327
333
|
coreos: Optional[bool]
|
|
334
|
+
console_log_file: Optional[str]
|
|
328
335
|
|
|
329
336
|
def __init__(self, name) -> None:
|
|
330
337
|
config_data = config.get_config()
|
|
@@ -342,6 +349,7 @@ class DomainConfiguration:
|
|
|
342
349
|
self.network_configuration = None
|
|
343
350
|
self.network_devices = []
|
|
344
351
|
self.tpm_configuration = None
|
|
352
|
+
self.console_log_file = None
|
|
345
353
|
self.virtiofs_configuration = []
|
|
346
354
|
self.iommu_configuration = None
|
|
347
355
|
self.qemu_args = []
|
|
@@ -367,6 +375,14 @@ class DomainConfiguration:
|
|
|
367
375
|
[device.generate() for device in self.network_devices + ([self.network_configuration] if self.network_configuration else [])]
|
|
368
376
|
)
|
|
369
377
|
|
|
378
|
+
def generate_serial_log_conf(self) -> str:
|
|
379
|
+
_serial_log_conf = ""
|
|
380
|
+
if self.console_log_file:
|
|
381
|
+
self._real_console_log_file = get_console_log_real_path(str(self.uuid))
|
|
382
|
+
_serial_log_conf = f'<log file="{self._real_console_log_file}" append="on"/>'
|
|
383
|
+
|
|
384
|
+
return _serial_log_conf
|
|
385
|
+
|
|
370
386
|
def get_emulator(self) -> str:
|
|
371
387
|
assert self.system_architecture is not None
|
|
372
388
|
qemu_paths = [
|
|
@@ -431,6 +447,7 @@ class DomainConfiguration:
|
|
|
431
447
|
{storage_devices}
|
|
432
448
|
{network_configuraton}
|
|
433
449
|
<serial type='pty'>
|
|
450
|
+
{serial_log_configuraton}
|
|
434
451
|
<target port='0'/>
|
|
435
452
|
</serial>
|
|
436
453
|
<console type='pty'>
|
|
@@ -459,6 +476,7 @@ class DomainConfiguration:
|
|
|
459
476
|
emulator_path=self.get_emulator(),
|
|
460
477
|
storage_devices=self.generate_storage_devices(),
|
|
461
478
|
network_configuraton=self.generate_network_devices(),
|
|
479
|
+
serial_log_configuraton=self.generate_serial_log_conf(),
|
|
462
480
|
tpm=self.tpm_configuration.generate() if self.tpm_configuration else "",
|
|
463
481
|
virtiofs_head=self.generate_virtiofs_head() if self.virtiofs_configuration else "",
|
|
464
482
|
virtiofs_device=self.generate_virtiofs_mounts() if self.virtiofs_configuration else "",
|
|
@@ -498,6 +516,7 @@ def _get_default_domain_conf(
|
|
|
498
516
|
domain_configuration = DomainConfiguration(name)
|
|
499
517
|
domain_configuration.cpu_count = vcpus
|
|
500
518
|
domain_configuration.memory_size = ram * 1024
|
|
519
|
+
domain_configuration.console_log_file = "{}/console.log".format(domain_configuration.path)
|
|
501
520
|
|
|
502
521
|
if desired_arch == "x86_64":
|
|
503
522
|
domain_configuration.system_architecture = X86_64ArchitectureConfiguration(
|
|
@@ -278,6 +278,34 @@ class Instance(object):
|
|
|
278
278
|
# create the dirs needed for this instance
|
|
279
279
|
try:
|
|
280
280
|
self._create_dirs()
|
|
281
|
+
if self.domain_configuration.console_log_file:
|
|
282
|
+
# SELinux is quite picky where it permits virtlogd to write logs,
|
|
283
|
+
# ConfigData.CONSOLE_LOG_DIR must point to location where virtlogd
|
|
284
|
+
# is permitted by SELinux to search, create the actual log file
|
|
285
|
+
# in the CONSOLE_LOG_DIR and point symlink to it
|
|
286
|
+
console_log_real_path = get_console_log_real_path(str(self.domain_configuration.uuid))
|
|
287
|
+
log.debug("Creating console log symlink {} -> {}".format(self.domain_configuration.console_log_file, console_log_real_path))
|
|
288
|
+
os.symlink(console_log_real_path, self.domain_configuration.console_log_file)
|
|
289
|
+
|
|
290
|
+
# Create an empty log file beforehand so the file will be
|
|
291
|
+
# accessible to testcloud. Otherwise libvirt will create a file
|
|
292
|
+
# only accessible to root.
|
|
293
|
+
with open(console_log_real_path, 'w'):
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
# Change label of log file to virt_log_t and give root permission to write
|
|
297
|
+
# this allows virtlogd to write to log file when testcloud runs with
|
|
298
|
+
# qemu:///system connection and SELinux is in enforcing mode
|
|
299
|
+
chcon_result = subprocess.call(["chcon", "-t", "virt_log_t", console_log_real_path])
|
|
300
|
+
if chcon_result == 0:
|
|
301
|
+
log.debug("Successfuly changed SELinux context of {}".format(console_log_real_path))
|
|
302
|
+
else:
|
|
303
|
+
log.error("Error changing SELinux context of {}".format(console_log_real_path))
|
|
304
|
+
setfacl_result = subprocess.call(["setfacl", "-m" "u:root:rw", console_log_real_path])
|
|
305
|
+
if setfacl_result == 0:
|
|
306
|
+
log.debug("Successfuly modified ACL of {}".format(console_log_real_path))
|
|
307
|
+
else:
|
|
308
|
+
log.error("Error modifying ACL of {}".format(console_log_real_path))
|
|
281
309
|
except PermissionError:
|
|
282
310
|
raise TestcloudPermissionsError
|
|
283
311
|
if not self.coreos:
|
|
@@ -736,7 +764,14 @@ class Instance(object):
|
|
|
736
764
|
"you have used a different connection?".format(self.name, self.connection)
|
|
737
765
|
)
|
|
738
766
|
|
|
739
|
-
def
|
|
767
|
+
def _remove_real_console_log(self):
|
|
768
|
+
# remove console log if it exists
|
|
769
|
+
console_log_real_path = get_console_log_real_path(self._get_domain().UUIDString())
|
|
770
|
+
if os.path.exists(console_log_real_path):
|
|
771
|
+
log.debug("Removing console log {}".format(console_log_real_path))
|
|
772
|
+
os.remove(console_log_real_path)
|
|
773
|
+
|
|
774
|
+
def remove(self, autostop=True, keep_console_log=True):
|
|
740
775
|
"""Remove an already stopped instance
|
|
741
776
|
|
|
742
777
|
:param bool autostop: if the instance is running, stop it first
|
|
@@ -758,7 +793,8 @@ class Instance(object):
|
|
|
758
793
|
"Cannot remove running instance {}. Please stop the "
|
|
759
794
|
"instance before removing or use '-f' parameter.".format(self.name)
|
|
760
795
|
)
|
|
761
|
-
|
|
796
|
+
if not keep_console_log:
|
|
797
|
+
self._remove_real_console_log()
|
|
762
798
|
self._remove_from_libvirt()
|
|
763
799
|
self._remove_from_disk()
|
|
764
800
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|