diff --git a/boottoolsfunctions/__init__.py b/boottoolsfunctions/__init__.py index ba421fc..2368017 100644 --- a/boottoolsfunctions/__init__.py +++ b/boottoolsfunctions/__init__.py @@ -5,11 +5,12 @@ import re import time import logging import subprocess +import shutil +import glob -logging.basicConfig (filename='/tmp/boot-tools_installation.log', filemode='a', format='%(levelname)s %(asctime)s (%(threadName)s) (%(funcName)s) %(message)s', level=logging.INFO) logger = logging.getLogger ('boottools') -def btogGetVar(osarch): +def btogGetVar (osarch): btdir = '/tmp/opengnsys_installer/opengnsys/client/boot-tools' bttargetdir = '/var/lib/tftpboot/ogclient/' btrootfsimg = os.path.join (bttargetdir, 'ogclient.img') @@ -23,7 +24,7 @@ def btogGetVar(osarch): btvirtualdisksize = '3G' return btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize -def btogGetOsInfo1(type_client): +def btogGetOsInfo1 (type_client): ogclientcfg = '/tmp/ogclient.cfg' if 'precise' == type_client: # ogLive 1.0.4-rc2 basado en Ubuntu 12.04 LTS. osdistrib='ubuntu' @@ -120,7 +121,7 @@ def btogGetOsInfo1(type_client): os.exit (1) return ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp -def btogGetOsInfo2(type_client, versionboottools, ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp): +def btogGetOsInfo2 (type_client, versionboottools, ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp): branch = 'master' giturl = 'https://api.github.com/repos/opengnsys/OpenGnsys/commits?sha={}&path=/client'.format (branch) gitrelease = 'r20240808' ## TODO: are we going to keep the following? $(curl -s "$GITURL" | jq -r '"r" + (.[0].commit.committer.date | split("-") | join("")[:8]) + "." + (.[0].sha[:7])') @@ -132,7 +133,7 @@ def btogGetOsInfo2(type_client, versionboottools, ogclientcfg, osdistrib, oscode #echo "$NAMEHOSTCLIENT" > /tmp/opengnsys_chroot # Generar fichero de configuración. - with open(ogclientcfg, 'w') as f: + with open (ogclientcfg, 'w') as f: print ('TYPECLIENT="{}"'.format (type_client), file=f) print ('OSDISTRIB="{}"'.format (osdistrib), file=f) print ('OSCODENAME="{}"'.format (oscodename), file=f) @@ -145,7 +146,7 @@ def btogGetOsInfo2(type_client, versionboottools, ogclientcfg, osdistrib, oscode return gitrelease, nameisoclient, namehostclient -def _run(args): +def _run (args): cp = subprocess.run (args, capture_output=True) if cp.returncode: logger.error ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode)) @@ -161,70 +162,152 @@ def _grep (regex, file): return 0 def _is_mounted (mntpt): - return _grep (mntpt, '/proc_mounts') + return _grep (mntpt, '/proc/mounts') def _umount (mntpt): if (_is_mounted (mntpt)): subprocess.run (['umount', mntpt]) -def btogSetFsVirtual(btrootfsimg, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch): +def btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch): #if not btrootfsimg: btogGetVar() - logger.info ('Creación y formateo del disco virtual "{}" MB'.format (btvirtualdisksize)) + logger.info ('Creación y formateo del disco virtual "{}" "{}" MB'.format (btrootfsimg, btvirtualdisksize)) try: _umount (btrootfsmnt) - except: return 1 + except: pass if (_is_mounted (btrootfsmnt)): - logger.error ('failed to umount "{}"'.format (btrootfsmnt)) - return 1 + raise Exception ('failed to umount "{}"'.format (btrootfsmnt)) - if (not os.makedirs (btrootfsmnt)): - logger.error ('Creando directorio "{}" : ERROR'.format (btrootfsmnt)) - return 1 + try: os.makedirs (btrootfsmnt, exist_ok=True) + except: + raise Exception ('Creando directorio "{}" : ERROR'.format (btrootfsmnt)) try: _run (['chown', '-R', 'root:opengnsys', bttargetdir]) - except: return 1 + except: + raise Exception ('Failed to chown root:opengnsys "{}"'.format (btrootfsmnt)) + logger.info ('Creating disk image "{}"'.format (btrootfsimg)) if 'i386' == osarch: try: _run (['dd', 'if=/dev/zero', 'of={}'.format (btrootfsimg), 'bs=1048576', 'count={}'.format (btvirtualdisksize)]) except: - logger.error ('Creando el disco virtual con tamaño maxima "{}" MB : ERROR'.format (btvirtualdisksize)) - return 2 + raise Exception ('Creando el disco virtual "{}" con tamaño maxima "{}" MB : ERROR'.format (btrootfsimg, btvirtualdisksize)) else: try: _run (['qemu-img', 'create', btrootfsimg, btvirtualdisksize]) except: - logger.error ('Creando el disco virtual con tamaño maxima "{}" MB : ERROR'.format (btvirtualdisksize)) - return 2 + raise Exception ('Creando el disco virtual "{}" con tamaño maxima "{}" MB : ERROR'.format (btrootfsimg, btvirtualdisksize)) - diskloop, _ = _run (['losetup', '-f']) + logger.debug ('losetup --find') + diskloop, _ = _run (['losetup', '--find']) if not diskloop: - logger.error ('no diskloop') - return 2 - print (diskloop) + raise Exception ('no diskloop') + logger.debug ('losetup attach') try: _run (['losetup', diskloop, btrootfsimg]) - except: return 2 + except: raise Exception ('losetup failed') - subprocess.run ("echo -e \"n\np\n1\n\n\nt\n83\nw\" |fdisk {}".format (diskloop), shell=True) + logger.info ('Partitioning disk image') + cp = subprocess.run(['bash', '-c', "echo $'n\np\n1\n\n\nt\n83\nw' |fdisk {}".format (diskloop)], capture_output=True) + logger.debug ('fdisk output follows: {}'.format (cp.stdout.decode('utf-8'))) - time.sleep (10) - try: _run (['losetup', '-d', diskloop]) + time.sleep (5) + logger.debug ('losetup --detach') + try: _run (['losetup', '--detache', diskloop]) except: - logger.error ('Liberando disco virtual despues del particionado: ERROR') - return 2 + raise Exception ('Liberando disco virtual despues del particionado: ERROR') - partloop, _ = _run (['losetup', '-f']) - _run (['losetup', '-o', '32256', partloop, btrootfsimg]) + logger.debug ('losetup --find') + partloop, _ = _run (['losetup', '--find']) + if not partloop: + raise Exception ('no partloop') + + logger.debug ('losetup --offset attach') + _run (['losetup', '--offset', '32256', partloop, btrootfsimg]) + + logger.info ('Creating ext4 filesystem') try: _run (['mkfs.ext4', '-b', '4096', '-L', btrootfsimglabel, partloop]) except: - logger.error ('Formateando la particion principal del disco virtual: ERROR') - return 2 + raise Exception ('Formateando la particion principal del disco virtual: ERROR') - time.sleep (10) - try: _run (['losetup', '-d', partloop]) + time.sleep (5) + logger.debug ('losetup --detach') + try: _run (['losetup', '--detach', partloop]) except: - logger.error ('Liberando la particion virtual despues del formateo: ERROR') - return 2 + raise Exception ('Liberando la particion virtual despues del formateo: ERROR') logger.info ('"{}" "{}" MB : OK'.format (btrootfsimg, btvirtualdisksize)) + +#btogSetFsAcces: habilita el acceso al sistema root del cliente con schroot +def btogSetFsAccess (btrootfsimg): + if (_grep (btrootfsimg, '/etc/schroot/schroot.conf')): + return + logger.info ('Iniciando la configuración del schroot') + + #cp /etc/schroot/schroot.conf /etc/schroot/schroot.conf.`getDateTime` + if (os.path.exists ('/etc/schroot/schroot.conf')): + shutil.copy ('/etc/schroot/schroot.conf', '/etc/schroot/schroot.conf.bak') + + with open ('/etc/schroot/schroot.conf', 'w') as f: + print ('[IMGogclient]', file=f) + print ('type=loopback', file=f) + print ('file=/var/lib/tftpboot/ogclient/ogclient.img', file=f) + print ('description=ogclient Ubuntu image', file=f) + print ('#priority=1', file=f) + print ('users=root', file=f) + print ('groups=root', file=f) + print ('root-groups=root', file=f) + print ('mount-options=-o offset=32256', file=f) + print ('root-users=root', file=f) + + #cp /etc/schroot/mount-defaults /etc/schroot/mount-defaults.`getDateTime` + if (os.path.exists ('/etc/schroot/mount-defaults')): + shutil.copy ('/etc/schroot/mount-defaults', '/etc/schroot/mount-defaults.bak') + + with open ('/etc/schroot/mount-defaults', 'w') as f: + print ('# mount.defaults: static file system information for chroots.', file=f) + print ('# Note that the mount point will be prefixed by the chroot path', file=f) + print ('# (CHROOT_PATH)', file=f) + print ('#', file=f) + print ('# ', file=f) + print ('proc /proc proc defaults 0 0', file=f) + print ('#procbususb /proc/bus/usb usbfs defaults 0 0', file=f) + print ('#/dev /dev none rw,bind 0 0', file=f) + print ('/dev/pts /dev/pts none rw,bind 0 0', file=f) + print ('/dev/shm /dev/shm none rw,bind 0 0', file=f) + print ('#/home /home none rw,bind 0 0', file=f) + print ('/tmp /tmp none rw,bind 0 0', file=f) + + map (os.unlink, glob.glob('/etc/schroot/setup.d/*chrootname')) + #for i in glob.glob ('/etc/schroot/setup.d/*chrootname'): + # os.unlink (i) + + logger.info ('Finalizado: OK') + return 0 + +# btogSetfsBase: Genera el sistema root base con debootstrap +def btogSetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp): + logger.info ('Iniciando la generación del sistema de archivos') + + #mount | grep $BTROOTFSMNT || mount $BTROOTFSIMG $BTROOTFSMNT -o loop,offset=32256 + if (not _is_mounted (btrootfsmnt)): + try: _run (['mount', btrootfsimg, btrootfsmnt, '-o', 'loop,offset=32256']) + except: + raise Exception ('mount failed') + + #mount | grep $BTROOTFSMNT && echoAndLog "$FUNCNAME: mount $BTROOTFSIMG $BTROOTFSMNT -o loop,offset=32256 OK " || errorAndLog "$FUNCNAME: mount $BTROOTFSIMG $BTROOTFSMNT -o loop,offset=32256 : FAILURE " + if (_is_mounted (btrootfsmnt)): + logger.info ('mount "{}" "{}" -o loop,offset=32256 OK'.format (btrootfsimg, btrootfsmnt)) + else: + raise Exception ('mount "{}" "{}" -o loop,offset=32256 : FAILURE'.format (btrootfsimg, btrootfsmnt)) + + logger.info ('debootstrapping system') + try: _run (['debootstrap', '--arch="{}"'.format(osarch), '--components=main,universe', oscodename, btrootfsmnt, oshttp]) + except: + if (_is_mounted (btrootfsmnt)): + subprocess.run (['umount', btrootfsmnt]) + raise Exception ('debootstrap --arch={} --components=main,universe "{}" "{}" "{}" : ha fallado!'.format (osarch, oscodename, btrootfsmnt, oshttp)) + + if (_is_mounted (btrootfsmnt)): + subprocess.run (['umount', btrootfsmnt]) + logger.info ('debootstrap --arch="{}" --components=main,universe "{}" "{}" "{}" : ok'.format (osarch, oscodename, btrootfsmnt, oshttp)) + return 0 diff --git a/boottoolsgenerator.py b/boottoolsgenerator.py index 5325de9..d238da5 100755 --- a/boottoolsgenerator.py +++ b/boottoolsgenerator.py @@ -3,15 +3,22 @@ import sys import os import logging +import subprocess +import glob +import stat sys.path.insert (0, __file__) -from boottoolsfunctions import btogGetOsInfo1, btogGetOsInfo2, btogGetVar +from boottoolsfunctions import btogGetOsInfo1, btogGetOsInfo2, btogGetVar, btogSetFsVirtual, btogSetFsAccess, btogSetFsBase -logging.basicConfig (filename='/tmp/boot-tools_installation.log', filemode='a', format='%(levelname)s %(asctime)s (%(threadName)s) (%(funcName)s) %(message)s', level=logging.INFO) +logging.basicConfig (filename='/tmp/boot-tools_installation.log', filemode='a', format='%(levelname)s %(asctime)s (%(funcName)s) %(message)s', level=logging.INFO) logger = logging.getLogger ('boottools') -#BRANCH = 'branches/master' -#svn export --force https://github.com/opengnsys/OpenGnsys/$BRANCH/client /tmp/opengnsys_installer/opengnsys/client +if not os.path.exists ('/tmp/opengnsys_installer/opengnsys/client/engine'): + branch = 'main' + tmpdir = subprocess.run (['mktemp', '--tmpdir', '--directory', 'oggit.XXXXXX'], capture_output=True).stdout.decode ('utf-8').strip() + subprocess.run (['git', 'clone', '-c', 'http.sslVerify=false', '--branch', branch, 'https://ognproject.evlt.uma.es/gitea/opengnsys/opengnsys.git', tmpdir]) + subprocess.run (['rsync', '-aHv', '{}/client/engine'.format(tmpdir), '{}/client/shared'.format(tmpdir), '/tmp/opengnsys_installer/opengnsys/client/']) + subprocess.run (['rm', '-rf', tmpdir]) type_client = sys.argv[1] if len(sys.argv)>1 else 'host' #WORKDIR = '/tmp/opengnsys_installer' @@ -33,101 +40,121 @@ os.chdir ('/tmp') ####################################################################3 logger.info ('FASE 1 - Asignación de variables') ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp = btogGetOsInfo1(type_client) -print (osarch) btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize = btogGetVar(osarch) -print (btdir) gitrelease, nameisoclient, namehostclient = btogGetOsInfo2(type_client, versionboottools, ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp) -print (nameisoclient) logger.info ('OpenGnsys CLIENT installation begins') ########################################################################## logger.info ('FASE 2 - Instalación de software adicional.') -""" #grep "http://free.nchc.org.tw/drbl-core" /etc/apt/sources.list || echo "deb http://free.nchc.org.tw/drbl-core drbl stable" >> /etc/apt/sources.list -apt-get update >>/tmp/fase2.out -[ -n "$(apt-cache search gpxe)" ] && PXEPKG="gpxe" -[ -n "$(apt-cache search ipxe)" ] && PXEPKG="ipxe" -apt-get -y install debootstrap subversion schroot squashfs-tools syslinux genisoimage $PXEPKG qemu qemu-utils lsof >>/tmp/fase2.out +subprocess.run (['apt-get', 'update']) #>>/tmp/fase2.out +acse_gpxe = subprocess.run (['apt-cache', 'search', 'gpxe'], capture_output=True).stdout.decode ('utf-8').strip() +acse_ipxe = subprocess.run (['apt-cache', 'search', 'ipxe'], capture_output=True).stdout.decode ('utf-8').strip() +if acse_ipxe: + pxepkg = 'ipxe' +elif acse_gpxe: + pxepkg = 'gpxe' +else: + logger.error ('neither gpxe nor ipxe found in apt-cache') + os._exit (1) +logger.info ('PXE package is "{}"'.format (pxepkg)) +## TODO qemu no existe, hace falta? +subprocess.run (['apt-get', '-y', 'install', 'debootstrap', 'subversion', 'schroot', 'squashfs-tools', 'syslinux', 'genisoimage', 'qemu-utils', 'lsof', pxepkg]) #>>/tmp/fase2.out ###################################################################3 logger.info ('FASE 3 - Creación del Sistema raiz RootFS (Segundo Sistema archivos (img))') logger.info ('Fase 3.1 Generar y formatear el disco virtual. Generar el dispositivo loop.') -file $BTROOTFSIMG | grep "partition 1: ID=0x83" -if [ $? == 1 ]: - btogSetFsVirtual || exit 2 - echo ================= nati after btogSetFsVirtual; ls -la /opt/opengnsys/tftpboot/ogclient/ +rc = subprocess.run ('file {} |grep -q "partition 1 *: ID=0x83"'.format (btrootfsimg), shell=True).returncode +print (rc) +if (rc): ## 'file|grep' failed + try: btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch) + except Exception as e: + logger.error (str (e)) + os._exit (2) + #echo ================= nati after btogSetFsVirtual; ls -la /opt/opengnsys/tftpboot/ogclient/ -logger.info ('Fase 3.2 Generar sistema de archivos con debootstrap') -schroot -p -c IMGogclient -- touch /tmp/ogclientOK -if [ -f /tmp/ogclientOK ] -then - rm /tmp/ogclientOK -else - btogSetFsBase >>/tmp/fase3.out -fi -echo ================= nati after fase 3; ls -la /opt/opengnsys/tftpboot/ogclient/ +logger.info ('Fase 3.2 - Configurar acceso schroot al Segundo Sistema de archivos (img)') +#cat /etc/schroot/schroot.conf | grep $BTROOTFSIMG || btogSetFsAccess +btogSetFsAccess (btrootfsimg) - -###################################################################3 -logger.info ('FASE 4 - Configurar acceso schroot al Segundo Sistema de archivos (img)') -cat /etc/schroot/schroot.conf | grep $BTROOTFSIMG || btogSetFsAccess +logger.info ('Fase 3.3 Generar sistema de archivos con debootstrap') +logger.debug ('Try creation of a file within chroot (this operation may fail--that is ok)') +cp = subprocess.run (['schroot', '--preserve-environment', '--chroot', 'IMGogclient', '--', 'touch', '/tmp/ogclientOK']) +if (cp.returncode): + try: btogSetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp) #>>/tmp/fase3.out + except Exception as e: + logger.error (str (e)) + os._exit (3) +else: + os.unlink ('/tmp/ogclientOK') +#echo ================= nati after fase 3; ls -la /opt/opengnsys/tftpboot/ogclient/ ########################################################################### -logger.info ('FASE 5 - Incorporando ficheros OpenGnsys al sistema raíz rootfs') -cp -a ${BTDIR}/includes/usr/bin/* /tmp >>/tmp/fase5.out -chmod +x /tmp/boot-tools/*.sh +logger.info ('FASE 4 - Incorporando ficheros OpenGnsys al sistema raíz rootfs') + +#cp -a ${BTDIR}/includes/usr/bin/* /tmp >>/tmp/fase5.out +subprocess.run (['cp', '-a'] + glob.glob ('{}/includes/usr/bin/*'.format (btdir)) + ['/tmp']) + +#chmod +x /tmp/boot-tools/*.sh +for i in glob.glob ('/tmp/boot-tools/*.sh'): + st = os.stat (i) + os.chmod (i, st.st_mode|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH) + # Incluir revisión. -sed -i "1 s/$/ $GITRELEASE ($OSRELEASE)/" ${BTDIR}/includes/etc/initramfs-tools/scripts/VERSION.txt +#sed -i "1 s/$/ $GITRELEASE ($OSRELEASE)/" ${BTDIR}/includes/etc/initramfs-tools/scripts/VERSION.txt +subprocess.run (['sed', '-i', '1 s/$/ {} ({})/'.format (gitrelease, osrelease), '{}/includes/etc/initramfs-tools/scripts/VERSION.txt'.format (btdir)]) + # En Ubuntu 13.04+ es necesario matar proceso de "udev" antes de desmontar. -umount $BTROOTFSMNT 2>/dev/null || (kill -9 $(lsof -t $BTROOTFSMNT); umount $BTROOTFSMNT) 2>/dev/null -schroot -p -c IMGogclient -- /tmp/boot-tools/boottoolsFsOpengnsys.sh >>/tmp/fase5.out +#umount $BTROOTFSMNT 2>/dev/null || (kill -9 $(lsof -t $BTROOTFSMNT); umount $BTROOTFSMNT) 2>/dev/null +""" +schroot --preserve-environment --chroot IMGogclient -- /tmp/boot-tools/boottoolsFsOpengnsys.sh >>/tmp/fase4.out ############################################################################################ -logger.info ('FASE 6 - Instalar software') -logger.info ('Fase 6.1 instalar paquetes deb con apt-get') -schroot -p -c IMGogclient -- /usr/bin/boot-tools/boottoolsSoftwareInstall.sh >>/tmp/fase6.out -logger.info ('Fase 6.2 compilar software.') +logger.info ('FASE 5 - Instalar software') +logger.info ('Fase 5.1 instalar paquetes deb con apt-get') +schroot --preserve-environment --chroot IMGogclient -- /usr/bin/boot-tools/boottoolsSoftwareInstall.sh >>/tmp/fase5.out +logger.info ('Fase 5.2 compilar software.') cd / -schroot -p -c IMGogclient -- /usr/bin/boot-tools/boottoolsSoftwareCompile.sh >>/tmp/fase6.out +schroot --preserve-environment --chroot IMGogclient -- /usr/bin/boot-tools/boottoolsSoftwareCompile.sh >>/tmp/fase5.out cd - ############################################################################################ -logger.info ('FASE 7 - Personalizar el sistema creado') -logger.info ('Fase 7.1 Incorporar la clave publica del servidor') +logger.info ('FASE 6 - Personalizar el sistema creado') +logger.info ('Fase 6.1 Incorporar la clave publica del servidor') cd / ssh-keygen -q -f /root/.ssh/id_rsa -N "" cp /root/.ssh/id_rsa.pub /tmp -schroot -p -c IMGogclient -- /usr/bin/boot-tools/boottoolsSshServer.sh +schroot --preserve-environment --chroot IMGogclient -- /usr/bin/boot-tools/boottoolsSshServer.sh cd - -logger.info ('Fase 7.2. Incorpoar la clave publica del propio cliente') -schroot -p -c IMGogclient -- /usr/bin/boot-tools/boottoolsSshClient.sh +logger.info ('Fase 6.2. Incorpoar la clave publica del propio cliente') +schroot --preserve-environment --chroot IMGogclient -- /usr/bin/boot-tools/boottoolsSshClient.sh -logger.info ('Fase 7.3. Configurando las locales') -schroot -p -c IMGogclient -- /usr/bin/boot-tools/boottoolsFsLocales.sh +logger.info ('Fase 6.3. Configurando las locales') +schroot --preserve-environment --chroot IMGogclient -- /usr/bin/boot-tools/boottoolsFsLocales.sh for i in `mount | grep IMGogclient | grep /var | cut -f3 -d" "`; do echo $i; umount $i; done for i in `mount | grep IMGogclient | grep /var | cut -f3 -d" "`; do echo $i; umount $i; done for i in `mount | grep IMGogclient | grep /var | cut -f3 -d" "`; do echo $i; umount $i; done -echo ================= nati after fase 7; ls -la /opt/opengnsys/tftpboot/ogclient/ +echo ================= nati after fase 6; ls -la /opt/opengnsys/tftpboot/ogclient/ ######################################################################### -logger.info ('FASE 8 - Generar distribucion') -logger.info ('Fase 8.1 Generar el initrd') -btogFsInitrd >>/tmp/fase8.out +logger.info ('FASE 7 - Generar distribucion') +logger.info ('Fase 7.1 Generar el initrd') +btogFsInitrd >>/tmp/fase7.out echo ================= nati after fase 8.1; ls -la /opt/opengnsys/tftpboot/ogclient/ -logger.info ('Fase 8.2 Generar fichero sqfs a partir del fichero img') +logger.info ('Fase 7.2 Generar fichero sqfs a partir del fichero img') btogFsSqfs echo ================= nati after fase 8.2; ls -la /opt/opengnsys/tftpboot/ogclient/ umount $BTROOTFSMNT 2>/dev/null -logger.info ('Fase 8.3 Generar la ISO') -btogIsoGenerator >>/tmp/fase8.out +logger.info ('Fase 7.3 Generar la ISO') +btogIsoGenerator >>/tmp/fase7.out echo ================= nati after fase 8.3; ls -la /opt/opengnsys/tftpboot/ogclient/ echoAndLog "OpenGnsys installation finished at $(date)"