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.
Files changed (50) hide show
  1. {testcloud-0.11.6/testcloud.egg-info → testcloud-0.11.7}/PKG-INFO +1 -1
  2. {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/conf.py +1 -1
  3. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/__init__.py +1 -1
  4. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/cli.py +1 -1
  5. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/config.py +4 -0
  6. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/domain_configuration.py +19 -0
  7. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/instance.py +38 -2
  8. {testcloud-0.11.6 → testcloud-0.11.7/testcloud.egg-info}/PKG-INFO +1 -1
  9. {testcloud-0.11.6 → testcloud-0.11.7}/.gitignore +0 -0
  10. {testcloud-0.11.6 → testcloud-0.11.7}/LICENSE +0 -0
  11. {testcloud-0.11.6 → testcloud-0.11.7}/README.md +0 -0
  12. {testcloud-0.11.6 → testcloud-0.11.7}/conf/99-testcloud-nonroot-libvirt-access.rules +0 -0
  13. {testcloud-0.11.6 → testcloud-0.11.7}/conf/settings-example.py +0 -0
  14. {testcloud-0.11.6 → testcloud-0.11.7}/conf/testcloud +0 -0
  15. {testcloud-0.11.6 → testcloud-0.11.7}/docs/LICENSE +0 -0
  16. {testcloud-0.11.6 → testcloud-0.11.7}/docs/Makefile +0 -0
  17. {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/api.rst +0 -0
  18. {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/indepth.rst +0 -0
  19. {testcloud-0.11.6 → testcloud-0.11.7}/docs/source/index.rst +0 -0
  20. {testcloud-0.11.6 → testcloud-0.11.7}/manpages/testcloud.1 +0 -0
  21. {testcloud-0.11.6 → testcloud-0.11.7}/pyproject.toml +0 -0
  22. {testcloud-0.11.6 → testcloud-0.11.7}/requirements.txt +0 -0
  23. {testcloud-0.11.6 → testcloud-0.11.7}/run_testcloud.py +0 -0
  24. {testcloud-0.11.6 → testcloud-0.11.7}/setup.cfg +0 -0
  25. {testcloud-0.11.6 → testcloud-0.11.7}/setup.py +0 -0
  26. {testcloud-0.11.6 → testcloud-0.11.7}/test/__init__.py +0 -0
  27. {testcloud-0.11.6 → testcloud-0.11.7}/test/test_cli.py +0 -0
  28. {testcloud-0.11.6 → testcloud-0.11.7}/test/test_config.py +0 -0
  29. {testcloud-0.11.6 → testcloud-0.11.7}/test/test_image.py +0 -0
  30. {testcloud-0.11.6 → testcloud-0.11.7}/test/test_instance.py +0 -0
  31. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/__init__.py +0 -0
  32. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/alma.py +0 -0
  33. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/centos.py +0 -0
  34. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/debian.py +0 -0
  35. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/fedora.py +0 -0
  36. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/misc.py +0 -0
  37. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/oracle.py +0 -0
  38. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/rocky.py +0 -0
  39. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/distro_utils/ubuntu.py +0 -0
  40. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/exceptions.py +0 -0
  41. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/image.py +0 -0
  42. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/sql.py +0 -0
  43. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/util.py +0 -0
  44. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud/workarounds.py +0 -0
  45. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/SOURCES.txt +0 -0
  46. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/dependency_links.txt +0 -0
  47. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/entry_points.txt +0 -0
  48. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/requires.txt +0 -0
  49. {testcloud-0.11.6 → testcloud-0.11.7}/testcloud.egg-info/top_level.txt +0 -0
  50. {testcloud-0.11.6 → testcloud-0.11.7}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: testcloud
3
- Version: 0.11.6
3
+ Version: 0.11.7
4
4
  Summary: A tool to download and boot cloud images locally, with an easy to use API.
5
5
  Home-page: https://pagure.io/testcloud
6
6
  Author: Mike Ruckman
@@ -55,7 +55,7 @@ copyright = "2016-2024, testCloud devs"
55
55
  # built documents.
56
56
  #
57
57
  # The short X.Y version.
58
- version = "0.11.6"
58
+ version = "0.11.7"
59
59
  # The full version, including alpha/beta/rc tags.
60
60
  release = version
61
61
 
@@ -1,5 +1,5 @@
1
1
  # NOTE: if you update version, *make sure* to also update `docs/source/conf.py`
2
- __version__ = "0.11.6"
2
+ __version__ = "0.11.7"
3
3
 
4
4
  import signal
5
5
  import sys
@@ -573,7 +573,7 @@ def _remove_instance(args):
573
573
  sys.exit(1)
574
574
 
575
575
  try:
576
- tc_instance.remove(autostop=args.force)
576
+ tc_instance.remove(autostop=args.force, keep_console_log=False)
577
577
  except TestcloudInstanceError as e:
578
578
  log.error(e)
579
579
  sys.exit(1)
@@ -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 remove(self, autostop=True):
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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: testcloud
3
- Version: 0.11.6
3
+ Version: 0.11.7
4
4
  Summary: A tool to download and boot cloud images locally, with an easy to use API.
5
5
  Home-page: https://pagure.io/testcloud
6
6
  Author: Mike Ruckman
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