Repository: cobbler/cobbler

Issue:
Buildiso: Errors in the logic for copying GRUB files
### Describe the bug

When using the `buildiso` command, the logic behind copying the GRUB files is wrong. It takes the supplied buildiso dir not into account and sticks to the default dir `buildiso`.

```bash
$ cobbler distro list
   testdistro

$ cobbler profile list
   testprofile1
   testprofile2
```

```bash
$ ll /var/cache/cobbler/
total 0
drwxr-xr-x 3 root root 22 Mar 15 17:02 buildiso1

$ cobbler buildiso --tempdir=/var/cache/cobbler/buildiso1 --iso=/var/cache/cobbler/autoinstall.iso --distro=testdistro
task started: 2022-03-15_170246_buildiso
task started (id=Build Iso, time=Tue Mar 15 17:02:46 2022)
running python triggers from /var/lib/cobbler/triggers/task/buildiso/pre/*
running shell triggers from /var/lib/cobbler/triggers/task/buildiso/pre/*
shell triggers finished successfully
Deleting and recreating the buildisodir at "/var/cache/cobbler/buildiso1/buildiso"
building tree for isolinux
building tree for GRUB 2
copying syslinux files
copying: /usr/share/syslinux/isolinux.bin -> /var/cache/cobbler/buildiso1/buildiso/isolinux/isolinux.bin
copying: /usr/share/syslinux/menu.c32 -> /var/cache/cobbler/buildiso1/buildiso/isolinux/menu.c32
copying: /usr/share/syslinux/chain.c32 -> /var/cache/cobbler/buildiso1/buildiso/isolinux/chain.c32
copying GRUB2 files
copying: /var/lib/cobbler/loaders/grub/grubx86.efi -> /var/cache/cobbler/buildiso/grub/grub.efi
Exception occurred: <class 'FileNotFoundError'>
Exception value: [Errno 2] No such file or directory: '/var/cache/cobbler/buildiso/grub/grub.efi'
Exception Info:
!!! TASK FAILED !!!
```

### Steps to reproduce

1. Run `cobbler buildiso` with `--tmpdir` that does not end with `buildiso`
3. See the command failing

### Expected behavior

The GRUB files should be copied to the correct place.

### Cobbler version

````bash
cobbler version
Cobbler 3.3.2
  source: ?, ?
  build time: Tue Mar 15 12:00:00 2022

````

### Operating system

```bash
$ cat /etc/os-release 
NAME="SLES"
VERSION="15-SP4"
VERSION_ID="15.4"
PRETTY_NAME="SUSE Linux Enterprise Server 15 SP4"
ID="sles"
ID_LIKE="suse"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:suse:sles:15:sp4"
DOCUMENTATION_URL="https://documentation.suse.com/"
```

### Cobbler log

```bash
[Thread-174] 2022-03-15T17:02:46 - INFO | REMOTE start_task(Build Iso); event_id(2022-03-15_170246_buildiso); user(?)[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - DEBUG | running python triggers from /var/lib/cobbler/triggers/task/buildiso/pre/*
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - DEBUG | running shell triggers from /var/lib/cobbler/triggers/task/buildiso/pre/*
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - DEBUG | shell triggers finished successfully
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | Deleting and recreating the buildisodir at "/var/cache/cobbler/buildiso1/buildiso"
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | building tree for isolinux
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | building tree for GRUB 2
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying syslinux files
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying: /usr/share/syslinux/isolinux.bin -> /var/cache/cobbler/buildiso1/buildiso/isolinux/isolinux.bin
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying: /usr/share/syslinux/menu.c32 -> /var/cache/cobbler/buildiso1/buildiso/isolinux/menu.c32
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying: /usr/share/syslinux/chain.c32 -> /var/cache/cobbler/buildiso1/buildiso/isolinux/chain.c32
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying GRUB2 files
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | copying: /var/lib/cobbler/loaders/grub/grubx86.efi -> /var/cache/cobbler/buildiso/grub/grub.efi
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | Exception occurred: <class 'FileNotFoundError'>
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | Exception value: [Errno 2] No such file or directory: '/var/cache/cobbler/buildiso/grub/grub.efi'
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - INFO | Exception Info:
  File "/usr/lib/python3.6/site-packages/cobbler/remote.py", line 99, in run
    rc = self._run(self)

  File "/usr/lib/python3.6/site-packages/cobbler/remote.py", line 174, in runner
    self.options.get("xorrisofs_opts", ""),

  File "/usr/lib/python3.6/site-packages/cobbler/api.py", line 1769, in build_iso
    distro_name=distro_name, systems=systems, exclude_dns=exclude_dns)

  File "/usr/lib/python3.6/site-packages/cobbler/actions/buildiso/netboot.py", line 565, in run
    buildisodir = self._prepare_iso(buildisodir, distro_name, profiles)

  File "/usr/lib/python3.6/site-packages/cobbler/actions/buildiso/__init__.py", line 291, in _prepare_iso
    self.__copy_files(iso_distro)

  File "/usr/lib/python3.6/site-packages/cobbler/actions/buildiso/__init__.py", line 181, in __copy_files
    utils.copyfile(str(grub_efi), str(grub_target), symlink=True)

  File "/usr/lib/python3.6/site-packages/cobbler/utils.py", line 1261, in copyfile
    if os.path.samefile(src, dst):

  File "/usr/lib64/python3.6/genericpath.py", line 97, in samefile
    s2 = os.stat(f2)
    
[2022-03-15_170246_buildiso] 2022-03-15T17:02:47 - ERROR | ### TASK FAILED ###
```


Discussion:

Resolving patch:
diff --git a/cobbler/actions/buildiso/__init__.py b/cobbler/actions/buildiso/__init__.py
--- a/cobbler/actions/buildiso/__init__.py
+++ b/cobbler/actions/buildiso/__init__.py
@@ -121,11 +121,12 @@ def filter_items(self, all_objs, selected_items: List[str]) -> list:
 
         return filtered_objects
 
-    def __copy_files(self, iso_distro):
+    def __copy_files(self, iso_distro, buildisodir: str = ""):
         """
         This method copies the required and optional files from syslinux into the directories we use for building the
         ISO.
         :param iso_distro: The distro (and thus architecture) to build the ISO for.
+        :param buildisodir: The directory where the ISO is being built in.
         """
         self.logger.info("copying syslinux files")
 
@@ -175,7 +176,7 @@ def __copy_files(self, iso_distro):
         grub_efi = bootloader_directory.joinpath(
             "grub", self.calculate_grub_name(iso_distro)
         )
-        buildiso_directory = pathlib.Path(self.api.settings().buildisodir)
+        buildiso_directory = pathlib.Path(buildisodir)
         grub_target = buildiso_directory.joinpath("grub", "grub.efi")
         if grub_efi.exists():
             utils.copyfile(str(grub_efi), str(grub_target), symlink=True)
@@ -288,7 +289,7 @@ def _prepare_iso(
                 'Not existent distribution name passed to "cobbler buildiso"!'
             ) from value_error
         buildisodir = self.__prepare_buildisodir(buildisodir)
-        self.__copy_files(iso_distro)
+        self.__copy_files(iso_distro, buildisodir)
         self.profiles = utils.input_string_or_list_no_inherit(profiles)
         return buildisodir
 


Test patch:
diff --git a/system-tests/tests/buildiso-@ b/system-tests/tests/buildiso-@
--- a/system-tests/tests/buildiso-@
+++ b/system-tests/tests/buildiso-@
@@ -45,6 +45,10 @@ case ${build_iso_test} in
     net)
         cobbler buildiso --tempdir="/var/cache/cobbler/buildiso" --iso ${tmp}/autoinst.iso --distro=leap-x86_64
         ;;
+    non-standard-directory)
+        mkdir /var/cache/cobbler/buildiso-test
+        cobbler buildiso --tempdir="/var/cache/cobbler/buildiso-test" --iso ${tmp}/autoinst.iso --distro=leap-x86_64
+        ;;
 esac
 
 # Check ISO exists & is bootable
diff --git a/system-tests/tests/buildiso-non-standard-directory b/system-tests/tests/buildiso-non-standard-directory
new file mode 120000
--- /dev/null
+++ b/system-tests/tests/buildiso-non-standard-directory
@@ -0,0 +1 @@
+buildiso-@
\ No newline at end of file