Compare commits

...

4 Commits

Author SHA1 Message Date
Natalia Serrano feae768405 refs #596 group chroot tasks in a single script 2024-08-16 12:43:26 +02:00
Natalia Serrano 9a6fecf90d refs #596 use apt modules rather than forking apt-get 2024-08-16 12:15:10 +02:00
Natalia Serrano 1bd24c9733 refs #596 separate more functions to their own module 2024-08-15 17:38:00 +02:00
Natalia Serrano 95a24ac6a6 refs #596 separate some functions to a new "utils" module 2024-08-14 15:57:54 +02:00
7 changed files with 226 additions and 284 deletions

View File

@ -1,35 +1,20 @@
#!/usr/bin/python3
import argparse
import shutil
import os
import glob
import sys
import re
import subprocess
from boottoolsfunctions import _run, _read_config
from boottoolsfunctions import utils, apt
config = _read_config ('boottoolsgenerator.cfg')
config = utils.read_config ('boottoolsgenerator.cfg')
if config is None:
sys.exit (1)
debconf_settings = config['General'].get ('debconf_settings')
def _aptget_clean():
_run (['apt-get', '--yes', 'clean'])
def _aptget_autoclean():
_run (['apt-get', '--yes', 'autoclean'])
def _aptget_autoremove():
_run (['apt-get', '--yes', 'autoremove'])
def _aptget_update():
_run (['apt-get', '--yes', 'update'])
def _aptget_upgrade():
_run (['apt-get', '--yes', 'upgrade'])
def _aptget_install (pkgs, opts=[]):
_run (['apt-get', '--yes'] + opts + ['install'] + pkgs)
debconf_settings2 = config['General'].get ('debconf_settings2')
def _oghook_deactivate():
#Desactivamos el hook del oginitrd.img para evitar problemas, al final de este escripts se activará
@ -55,55 +40,102 @@ def boottoolsSoftwareInstall (osarch, osrelease):
os.environ['LANG'] = 'C'
os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
stdout, _ = _run (['dpkg-divert', '--list'])
stdout, _ = utils.run (['dpkg-divert', '--list'])
if not re.findall (r'local diversion of /sbin/initctl to /sbin/initctl.distrib', stdout):
_run (['dpkg-divert', '--local', '--rename', '--add', '/sbin/initctl'])
utils.run (['dpkg-divert', '--local', '--rename', '--add', '/sbin/initctl'])
os.symlink ('/bin/true', '/sbin/initctl')
_aptget_clean()
pkgs32 = []
if 'i386' != osarch:
_run (['dpkg', '--add-architecture', 'i386'])
utils.run (['dpkg', '--add-architecture', 'i386'])
pkgs32 = 'lib32gcc-s1 lib32stdc++6 lib32z1 libc6-i386'.split (' ') ## he cambiado lib32gcc1 por lib32gcc-s1 pero como queramos crear un oglive viejo, esto va a petar
_aptget_update() ## esto ya esta hecho...
_oghook_deactivate()
_aptget_upgrade()
#_mock_mtab()
_aptget_install ([f'linux-image-{osrelease}', f'linux-headers-{osrelease}', f'linux-modules-{osrelease}', f'linux-modules-extra-{osrelease}', 'dkms', 'shim-signed', 'openssl'])
apt.install ([f'linux-image-{osrelease}', f'linux-headers-{osrelease}', f'linux-modules-{osrelease}', f'linux-modules-extra-{osrelease}', 'dkms', 'shim-signed', 'openssl'])
subprocess.run (['debconf-set-selections'], input=debconf_settings, text=True)
_aptget_install (['sshfs', 'kexec-tools'] + pkgs32, opts=['-o', 'DPkg::Options::=--force-confdef']) ## hace falta --force-confdef para evitar un tema interactivo del /etc/ssh/ssh_config
apt.install (['sshfs', 'kexec-tools'] + pkgs32, opts={'DPkg::Options::': '--force-confdef'}) ## hace falta --force-confdef para evitar un tema interactivo del /etc/ssh/ssh_config
pkgs = []
for section in config.options('Packages'):
pkgs += re.split (r'[ \n]', config['Packages'].get(section).strip())
print ('about to install these packages: "{}"'.format (' '.join (pkgs)))
## TODO don't fail when there are unknown/uninstallable packages
_aptget_install (pkgs)
apt.install (pkgs)
# Instalar módulos que algunos paquetes puedan tener pendientes de compilar.
stdout, _ = _run (['dkms', 'status'])
stdout, _ = utils.run (['dkms', 'status'])
for l in stdout.strip().split ('\n'):
if not l: continue
print (f'l "{l}"')
mod, vers, status = l.split (',')
if 'added' in status:
print (f'dkms installing {mod} {vers}')
_run (['dkms', 'install', '-m', mod.strip(), '-v', vers.strip()])
utils.run (['dkms', 'install', '-m', mod.strip(), '-v', vers.strip()])
_oghook_activate()
#_restore_mtab()
_aptget_clean()
_aptget_autoclean()
_aptget_autoremove()
apt.clean()
apt.autoremove()
def boottoolsSoftwareCompile():
os.environ['LANGUAGE'] = os.environ['LC_ALL'] = os.environ['LANG'] = 'C'
os.chdir ('/tmp')
print ('ms-sys')
try: utils.run (['which', 'ms-sys'])
except:
utils.run (['wget', 'https://sourceforge.net/projects/ms-sys/files/latest/download', '-O', 'ms-sys.tar.gz'])
utils.run (['tar', '-xpzf', 'ms-sys.tar.gz'])
mssys_dir = subprocess.run (['tar tzf ms-sys.tar.gz |head -n 1'], shell=True, capture_output=True, text=True).stdout.strip()
print (f'mssys_dir "{mssys_dir}"')
os.chdir (mssys_dir)
utils.run (['make', 'install'])
os.chdir ('..')
print ('spartlnx')
try: utils.run (['which', 'spartl64.run'])
except:
utils.run (['wget', 'http://damien.guibouret.free.fr/savepart.zip'])
utils.run (['unzip', '-o', 'savepart.zip', '-d', '/sbin/', 'spartl64.run'])
utils.run (['mkdir', '/usr/share/doc/spartlnx'])
utils.run (['unzip', '-j', '-o', 'savepart.zip', '-d', '/usr/share/doc/spartlnx/', 'doc/en/*'])
if not os.path.exists ('python-libfdisk'):
print ('python-libfdisk')
apt.install (['python3-psutil', 'python3-dev', 'libfdisk-dev', 'python3-setuptools'])
utils.run (['git', 'clone', 'git://git.48k.eu/python-libfdisk'])
os.chdir ('python-libfdisk')
utils.run (['python3', 'setup.py', 'install'])
os.chdir ('..')
apt.remove (['python3-dev', 'python3-setuptools'])
## TODO restore os.environ and pwd
os.environ['LANGUAGE'] = os.environ['LC_ALL'] = os.environ['LANG'] = 'C'
os.chdir ('/tmp')
def boottoolsFsLocales():
subprocess.run (['debconf-set-selections'], input=debconf_settings2, text=True)
## despues de esto, debconf-get-selections devuelve los valores antiguos, no se por que...
utils.run (['dpkg-reconfigure', '--frontend', 'noninteractive', 'console-setup', 'locales'])
def boottoolsInitrdGenerate (osrelease):
for f in glob.glob ('/usr/lib/initramfs-tools/bin/*'):
os.unlink (f)
shutil.copy ('/bin/busybox', '/usr/lib/initramfs-tools/bin')
os.chdir ('/tmp')
utils.run (['mkinitramfs', '-o', f'/tmp/initrd.img-{osrelease}', '-v', osrelease])
shutil.copy (f'/boot/vmlinuz-{osrelease}', '/tmp/')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument ('--osarch', help='OS architecture', action='store', required=True)
parser.add_argument ('--osrelease', help='OS release', action='store', required=True)
parser.add_argument ('--osarch', help='OS architecture', action='store', required=True)
parser.add_argument ('--osrelease', help='OS release', action='store', required=True)
args = parser.parse_args()
boottoolsSoftwareInstall (args.osarch, args.osrelease)
boottoolsSoftwareCompile()
boottoolsFsLocales()
boottoolsInitrdGenerate (args.osrelease)

View File

@ -1,36 +0,0 @@
#!/usr/bin/python3
import os
import subprocess
from boottoolsfunctions import _run
os.environ['LANGUAGE'] = os.environ['LC_ALL'] = os.environ['LANG'] = 'C'
os.chdir ('/tmp')
print ('ms-sys')
try: _run (['which', 'ms-sys'])
except:
_run (['wget', 'https://sourceforge.net/projects/ms-sys/files/latest/download', '-O', 'ms-sys.tar.gz'])
_run (['tar', '-xpzf', 'ms-sys.tar.gz'])
mssys_dir = subprocess.run (['tar tzf ms-sys.tar.gz |head -n 1'], shell=True, capture_output=True, text=True).stdout.strip()
print (f'mssys_dir "{mssys_dir}"')
os.chdir (mssys_dir)
_run (['make', 'install'])
os.chdir ('..')
print ('spartlnx')
try: _run (['which', 'spartl64.run'])
except:
_run (['wget', 'http://damien.guibouret.free.fr/savepart.zip'])
_run (['unzip', '-o', 'savepart.zip', '-d', '/sbin/', 'spartl64.run'])
_run (['mkdir', '/usr/share/doc/spartlnx'])
_run (['unzip', '-j', '-o', 'savepart.zip', '-d', '/usr/share/doc/spartlnx/', 'doc/en/*'])
if not os.path.exists ('python-libfdisk'):
print ('python-libfdisk')
_run (['apt-get', '-y', 'install', 'python3-psutil', 'python3-dev', 'libfdisk-dev', 'python3-setuptools'])
_run (['git', 'clone', 'git://git.48k.eu/python-libfdisk'])
os.chdir ('python-libfdisk')
_run (['python3', 'setup.py', 'install'])
os.chdir ('..')
_run (['apt-get', '-y', 'remove', 'python3-dev', 'python3-setuptools'])

View File

@ -1,15 +0,0 @@
#!/usr/bin/python3
import os
import subprocess
from boottoolsfunctions import _run, _read_config
config = _read_config ('boottoolsgenerator.cfg')
if config is None:
sys.exit (1)
debconf_settings2 = config['General'].get ('debconf_settings2')
subprocess.run (['debconf-set-selections'], input=debconf_settings2, text=True)
## despues de esto, debconf-get-selections devuelve los valores antiguos, no se por que...
_run (['dpkg-reconfigure', '--frontend', 'noninteractive', 'console-setup', 'locales'])

View File

@ -1,22 +0,0 @@
#!/usr/bin/python3
import argparse
import shutil
import os
import glob
from boottoolsfunctions import _run
def boottoolsInitrdGenerate (osrelease):
for f in glob.glob ('/usr/lib/initramfs-tools/bin/*'):
os.unlink (f)
shutil.copy ('/bin/busybox', '/usr/lib/initramfs-tools/bin')
os.chdir ('/tmp')
_run (['mkinitramfs', '-o', f'/tmp/initrd.img-{osrelease}', '-v', osrelease])
shutil.copy (f'/boot/vmlinuz-{osrelease}', '/tmp/')
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument ('--osrelease', help='OS release', action='store', required=True)
args = parser.parse_args()
boottoolsInitrdGenerate (args.osrelease)

View File

@ -1,13 +1,13 @@
import platform
import os
import re
import time
import logging
import subprocess
import shutil
import glob
import datetime
import configparser
from . import utils
logger = logging.getLogger ('boottools')
@ -39,54 +39,7 @@ proc /proc proc defaults 0 0
/tmp /tmp none rw,bind 0 0
""".strip()
def _run (args):
cp = subprocess.run (args, text=True, capture_output=True)
if cp.returncode:
logger.error ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode))
logger.error ('stdout follows:')
for i in cp.stdout.strip().split('\n'): logger.error (' ' + i)
logger.error ('stderr follows:')
for i in cp.stderr.strip().split('\n'): logger.error (' ' + i)
raise Exception ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode))
stdout = cp.stdout.strip()
stderr = cp.stderr.strip()
return stdout, stderr
def _grep (regex, file):
with open (file, 'r') as f:
for l in f:
if (re.findall (regex, l)): return 1
return 0
def _is_mounted (mntpt):
return _grep (mntpt, '/proc/mounts')
def _mount (dev, mntpt, opts=[]):
if not _is_mounted (mntpt):
_run (['mount', dev, mntpt] + opts)
def _umount (mntpt):
if (_is_mounted (mntpt)):
_run (['umount', mntpt])
def _read_config (fn):
if not os.path.exists (fn):
print (f'configuration file "{fn}" not found')
return
config = configparser.ConfigParser (comment_prefixes='#', inline_comment_prefixes='#')
config.read (fn)
return config
def _write_md5 (fn):
md5, _ = _run (['md5sum', fn])
md5, rest = md5.split (' ', 1)
with open (f'{fn}.sum', 'w') as fd:
fd.write (md5 + '\n')
def btogGetVar (osarch):
def GetVar (osarch):
btdir = '/tmp/opengnsys/oglive_builder'
bttargetdir = '/var/lib/tftpboot/ogclient/'
btrootfsimg = os.path.join (bttargetdir, 'ogclient.img')
@ -100,7 +53,7 @@ def btogGetVar (osarch):
btvirtualdisksize = '3G'
return btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize
def btogGetOsInfo1 (type_client):
def GetOsInfo1 (type_client):
if 'precise' == type_client: # ogLive 1.0.4-rc2 basado en Ubuntu 12.04 LTS.
osdistrib='ubuntu'
oscodename='precise'
@ -195,90 +148,90 @@ def btogGetOsInfo1 (type_client):
osdistrib=platform.freedesktop_os_release()['NAME']
oscodename=platform.freedesktop_os_release()['VERSION_CODENAME']
osrelease=platform.uname()[2]
osarch, _=_run (['dpkg', '--print-architecture'])
osarch, _=utils.run (['dpkg', '--print-architecture'])
oshttp='http://es.archive.ubuntu.com/ubuntu/'
else: # Parámetro desconocido
print ('Parámetro no válido.')
os.exit (1)
return osdistrib, oscodename, osrelease, osarch, oshttp
def btogGetOsInfo2 (ogrepo_dir, versionboottools, oscodename, osrelease, osarch):
def GetOsInfo2 (ogrepo_dir, versionboottools, oscodename, osrelease, osarch):
gitrelease = subprocess.run (['git', '--git-dir', f'{ogrepo_dir}/.git', 'log', '--date', 'format:r%Y%m%d', '--format=%ad', '-1'], capture_output=True, text=True).stdout.strip()
nameisoclient ='-'.join ([versionboottools, oscodename, osrelease, osarch, gitrelease])
namehostclient = '-'.join ([versionboottools, oscodename, gitrelease])
return gitrelease, nameisoclient, namehostclient
def btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch):
def SetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch):
logger.info (f'Creación y formateo del disco virtual "{btrootfsimg}" "{btvirtualdisksize}" MB')
try: _umount (btrootfsmnt)
try: utils.umount (btrootfsmnt)
except: pass
if (_is_mounted (btrootfsmnt)):
if (utils.is_mounted (btrootfsmnt)):
raise Exception (f'failed to umount "{btrootfsmnt}"')
try: os.makedirs (btrootfsmnt, exist_ok=True)
except:
raise Exception (f'Creando directorio "{btrootfsmnt}" : ERROR')
try: _run (['chown', '-R', 'root:opengnsys', bttargetdir])
try: utils.run (['chown', '-R', 'root:opengnsys', bttargetdir])
except:
raise Exception (f'Failed to chown root:opengnsys "{btrootfsmnt}"')
logger.info (f'Creating disk image "{btrootfsimg}"')
if 'i386' == osarch:
try: _run (['dd', 'if=/dev/zero', f'of={btrootfsimg}', 'bs=1048576', f'count={btvirtualdisksize}'])
try: utils.run (['dd', 'if=/dev/zero', f'of={btrootfsimg}', 'bs=1048576', f'count={btvirtualdisksize}'])
except:
raise Exception (f'Creando el disco virtual "{btrootfsimg}" con tamaño maxima "{btvirtualdisksize}" MB : ERROR')
else:
try: _run (['qemu-img', 'create', btrootfsimg, btvirtualdisksize])
try: utils.run (['qemu-img', 'create', btrootfsimg, btvirtualdisksize])
except:
raise Exception (f'Creando el disco virtual "{btrootfsimg}" con tamaño maxima "{btvirtualdisksize}" MB : ERROR')
logger.debug ('losetup --find')
diskloop, _ = _run (['losetup', '--find'])
diskloop, _ = utils.run (['losetup', '--find'])
if not diskloop:
raise Exception ('no diskloop')
logger.debug ('losetup attach')
try: _run (['losetup', '--partscan', diskloop, btrootfsimg])
try: utils.run (['losetup', '--partscan', diskloop, btrootfsimg])
except: raise Exception ('losetup failed')
logger.info ('Partitioning disk image')
stdout, _ = _run (['bash', '-c', f"echo $'n\np\n1\n\n\nt\n83\nw' |fdisk {diskloop}"])
stdout, _ = utils.run (['bash', '-c', f"echo $'n\np\n1\n\n\nt\n83\nw' |fdisk {diskloop}"])
logger.debug (f'fdisk stdout follows:')
for i in stdout.strip().split('\n'): logger.debug (' ' + i)
time.sleep (3)
logger.debug ('losetup --detach')
try: _run (['losetup', '--detach', diskloop])
try: utils.run (['losetup', '--detach', diskloop])
except:
raise Exception ('Liberando disco virtual despues del particionado: ERROR')
logger.debug ('losetup --find')
partloop, _ = _run (['losetup', '--find'])
partloop, _ = utils.run (['losetup', '--find'])
if not partloop:
raise Exception ('no partloop')
logger.debug ('losetup --offset attach')
_run (['losetup', '--offset', '32256', partloop, btrootfsimg])
utils.run (['losetup', '--offset', '32256', partloop, btrootfsimg])
logger.info ('Creating ext4 filesystem')
try: _run (['mkfs.ext4', '-b', '4096', '-L', btrootfsimglabel, partloop])
try: utils.run (['mkfs.ext4', '-b', '4096', '-L', btrootfsimglabel, partloop])
except:
raise Exception ('Formateando la particion principal del disco virtual: ERROR')
time.sleep (3)
logger.debug ('losetup --detach')
try: _run (['losetup', '--detach', partloop])
try: utils.run (['losetup', '--detach', partloop])
except:
raise Exception ('Liberando la particion virtual despues del formateo: ERROR')
logger.info (f'"{btrootfsimg}" "{btvirtualdisksize}" MB : OK')
#btogSetFsAcces: habilita el acceso al sistema root del cliente con schroot
def btogSetFsAccess (btrootfsimg):
if (_grep (btrootfsimg, '/etc/schroot/schroot.conf')):
#SetFsAcces: habilita el acceso al sistema root del cliente con schroot
def SetFsAccess (btrootfsimg):
if (utils.grep (btrootfsimg, '/etc/schroot/schroot.conf')):
return
logger.info ('Iniciando la configuración del schroot')
@ -298,20 +251,20 @@ def btogSetFsAccess (btrootfsimg):
logger.info ('Finalizado: OK')
return 0
# btogSetfsBase: Genera el sistema root base con debootstrap
# SetfsBase: Genera el sistema root base con debootstrap
# trabaja sobre un rootfs ya montado
def btogSetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp):
def SetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp):
logger.info ('Iniciando la generación del sistema de archivos')
logger.info ('debootstrapping system')
logger.debug (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}"')
try: _run (['debootstrap', f'--arch={osarch}', '--components=main,universe', oscodename, btrootfsmnt, oshttp])
try: utils.run (['debootstrap', f'--arch={osarch}', '--components=main,universe', oscodename, btrootfsmnt, oshttp])
except: raise Exception (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}" : ha fallado!')
logger.info (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}" : ok')
return 0
def boottoolsFsOpengnsys (builder, og_shared, og_engine, ogclientmount, osdistrib, oscodename):
def FsOpengnsys (builder, og_shared, og_engine, ogclientmount, osdistrib, oscodename):
print ('Iniciando la personalización con datos del repositorio')
sources_list_in = f'{builder}/includes/etc/apt/sources.list.{osdistrib.lower()}'
@ -349,9 +302,9 @@ def boottoolsFsOpengnsys (builder, og_shared, og_engine, ogclientmount, osdistri
if os.path.exists (f'{og_shared}/bin/browser'): shutil.copy (f'{og_shared}/bin/browser', f'{ogclientmount}/bin/')
if os.path.exists (f'{og_shared}/bin/ogAdmClient'): shutil.copy (f'{og_shared}/bin/ogAdmClient', f'{ogclientmount}/bin/')
def boottoolsSshServer (btrootfsmnt):
def SshServer (btrootfsmnt):
if not os.path.exists ('/root/.ssh/id_rsa'): ## crea un par de claves en la VM, no en el chroot
_run (['ssh-keygen', '-q', '-f', '/root/.ssh/id_rsa', '-N', ''])
utils.run (['ssh-keygen', '-q', '-f', '/root/.ssh/id_rsa', '-N', ''])
logger.debug ('comprobando directorio .ssh del root')
if not os.path.exists (f'{btrootfsmnt}/root/.ssh'): ## crea directorio dentro del chroot
@ -379,9 +332,9 @@ def boottoolsSshServer (btrootfsmnt):
else:
logger.error ('no key publica og')
def boottoolsSshClient (btrootfsmnt):
def SshClient (btrootfsmnt):
if not os.path.exists (f'{btrootfsmnt}/root/.ssh/id_rsa'):
_run (['ssh-keygen', '-q', '-f', f'{btrootfsmnt}/root/.ssh/id_rsa', '-N', '']) ## crea un par de claves en el chroot
utils.run (['ssh-keygen', '-q', '-f', f'{btrootfsmnt}/root/.ssh/id_rsa', '-N', '']) ## crea un par de claves en el chroot
#cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys ## coge la publica y se la autoriza a sí mismo
fdin = open (f'{btrootfsmnt}//root/.ssh/id_rsa.pub', 'r')
@ -396,8 +349,8 @@ def boottoolsSshClient (btrootfsmnt):
## TODO: exportamos la publica a los repos
#cp /root/.ssh/id_rsa.pub /tmp/rsa.ogclient.pub
#btogFsInitrd genera un initrd.
def btogFsInitrd (bttargetdir, osrelease):
#FsInitrd genera un initrd.
def FsInitrd (bttargetdir, osrelease):
#echo "cp /tmp/*-${OSRELEASE} ${BTTARGETDIR}"
#cp /tmp/*-${OSRELEASE} ${BTTARGETDIR} ## esto copia algo??
@ -413,15 +366,15 @@ def btogFsInitrd (bttargetdir, osrelease):
shutil.copy (f'/tmp/initrd.img-{osrelease}', f'{bttargetdir}/oginitrd.img')
shutil.copy (f'/tmp/vmlinuz-{osrelease}', f'{bttargetdir}/ogvmlinuz')
_write_md5 (f'{bttargetdir}/oginitrd.img')
_write_md5 (f'{bttargetdir}/ogvmlinuz')
utils.write_md5 (f'{bttargetdir}/oginitrd.img')
utils.write_md5 (f'{bttargetdir}/ogvmlinuz')
#chmod -R 755 $BTTARGETDIR
for f in glob.glob (f'{bttargetdir}/oginitrd*') + glob.glob (f'{bttargetdir}/vmlinuz*'):
os.chmod (f, 0o755)
#btogFsSqfs convierte el sistema root en sqfs
def btogFsSqfs (bttargetdir, btrootfsmnt):
#FsSqfs convierte el sistema root en sqfs
def FsSqfs (bttargetdir, btrootfsmnt):
logger.info ('Iniciando la creación del sistema de archivos en sqfs')
# si ya existe un sqfs lo renombramos
@ -429,13 +382,13 @@ def btogFsSqfs (bttargetdir, btrootfsmnt):
now = datetime.datetime.now(datetime.timezone.utc).strftime ('%Y%m%d-%H%M%S%z')
os.rename (f'{bttargetdir}/ogclient.sqfs', f'{bttargetdir}/ogclient.sqfs.{now}')
_run (['mksquashfs', btrootfsmnt, f'{bttargetdir}/ogclient.sqfs'])
utils.run (['mksquashfs', btrootfsmnt, f'{bttargetdir}/ogclient.sqfs'])
os.chmod (f'{bttargetdir}/ogclient.sqfs', 0o744)
_write_md5 (f'{bttargetdir}/ogclient.sqfs')
utils.write_md5 (f'{bttargetdir}/ogclient.sqfs')
# btogIsoGenerator genera la iso del cliente
def btogIsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient):
# IsoGenerator genera la iso del cliente
def IsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient):
#Preparamos los gestores de arranque
try: os.makedirs ('/tmp/iso/isolinux', exist_ok=True)
except: raise
@ -452,9 +405,9 @@ def btogIsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient):
# Si existe el fichero ISO, montarlo para extraer isolinux.bin.
if os.path.exists (f'/tmp/iso/isolinux/{pxepkg}.iso'):
os.mkdir ('/tmp/iso/isolinux/mount')
_run (['mount', '-o', 'loop', f'/tmp/iso/isolinux/{pxepkg}.iso', '/tmp/iso/isolinux/mount'])
utils.run (['mount', '-o', 'loop', f'/tmp/iso/isolinux/{pxepkg}.iso', '/tmp/iso/isolinux/mount'])
subprocess.run (['cp -a /tmp/iso/isolinux/mount/* /tmp/iso/isolinux'], shell=True)
_umount ('/tmp/iso/isolinux/mount')
utils.umount ('/tmp/iso/isolinux/mount')
os.rmdir ('/tmp/iso/isolinux/mount')
os.unlink (f'/tmp/iso/isolinux/{pxepkg}.iso')
@ -478,9 +431,9 @@ def btogIsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient):
oldpwd = os.getcwd()
os.chdir ('/tmp')
logger.debug (f'mkisofs -V ogClient -o {nameisoclient}.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -J -no-emul-boot -boot-load-size 4 -boot-info-table /tmp/iso')
_run (['mkisofs', '-V', 'ogClient', '-o', f'{nameisoclient}.iso', '-b', 'isolinux/isolinux.bin', '-c', 'isolinux/boot.cat', '-J', '-no-emul-boot', '-boot-load-size', '4', '-boot-info-table', '/tmp/iso'])
utils.run (['mkisofs', '-V', 'ogClient', '-o', f'{nameisoclient}.iso', '-b', 'isolinux/isolinux.bin', '-c', 'isolinux/boot.cat', '-J', '-no-emul-boot', '-boot-load-size', '4', '-boot-info-table', '/tmp/iso'])
_write_md5 (f'{nameisoclient}.iso')
utils.write_md5 (f'{nameisoclient}.iso')
os.chdir (oldpwd)
os.rename (f'/tmp/{nameisoclient}.iso' , f'/var/lib/tftpboot/ogclient/{nameisoclient}.iso')

View File

@ -0,0 +1,54 @@
import logging
import subprocess
import re
import os
import configparser
logger = logging.getLogger ('boottools')
def run (args):
cp = subprocess.run (args, text=True, capture_output=True)
if cp.returncode:
logger.error ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode))
logger.error ('stdout follows:')
for i in cp.stdout.strip().split('\n'): logger.error (' ' + i)
logger.error ('stderr follows:')
for i in cp.stderr.strip().split('\n'): logger.error (' ' + i)
raise Exception ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode))
stdout = cp.stdout.strip()
stderr = cp.stderr.strip()
return stdout, stderr
def grep (regex, file):
with open (file, 'r') as f:
for l in f:
if (re.findall (regex, l)): return 1
return 0
def is_mounted (mntpt):
return grep (mntpt, '/proc/mounts')
def mount (dev, mntpt, opts=[]):
if not is_mounted (mntpt):
run (['mount', dev, mntpt] + opts)
def umount (mntpt):
if (is_mounted (mntpt)):
run (['umount', mntpt])
def read_config (fn):
if not os.path.exists (fn):
print (f'configuration file "{fn}" not found')
return
config = configparser.ConfigParser (comment_prefixes='#', inline_comment_prefixes='#')
config.read (fn)
return config
def write_md5 (fn):
md5, _ = run (['md5sum', fn])
md5, rest = md5.split (' ', 1)
with open (f'{fn}.sum', 'w') as fd:
fd.write (md5 + '\n')

View File

@ -10,7 +10,7 @@ import shutil
curdir = os.path.dirname (__file__)
sys.path.insert (0, curdir)
from boottoolsfunctions import _run, _mount, _umount, _read_config, btogGetOsInfo1, btogGetOsInfo2, btogGetVar, btogSetFsVirtual, btogSetFsAccess, btogSetFsBase, boottoolsFsOpengnsys, boottoolsSshServer, boottoolsSshClient, btogFsInitrd, btogFsSqfs, btogIsoGenerator
from boottoolsfunctions import utils, apt, btog
def _logging():
#logging.root.handlers = []
@ -31,57 +31,54 @@ def _logging():
def clone_client_dirs (ogrepo_url, ogrepo_branch, ogrepo_dir):
if not os.path.exists ('/tmp/opengnsys/engine'):
_run (['git', 'clone', '-c', 'http.sslVerify=false', '--branch', ogrepo_branch, ogrepo_url, ogrepo_dir])
_run (['rsync', '-aH', f'{ogrepo_dir}/client/engine', f'{ogrepo_dir}/client/shared', '/tmp/opengnsys/'])
utils.run (['git', 'clone', '-c', 'http.sslVerify=false', '--branch', ogrepo_branch, ogrepo_url, ogrepo_dir])
utils.run (['rsync', '-aH', f'{ogrepo_dir}/client/engine', f'{ogrepo_dir}/client/shared', '/tmp/opengnsys/'])
def _mount_rootfs():
global btrootfsimg, btrootfsmnt
try: _mount (btrootfsimg, btrootfsmnt, opts=['-o', 'loop,offset=32256'])
try: utils.mount (btrootfsimg, btrootfsmnt, opts=['-o', 'loop,offset=32256'])
except:
logger.error ('mount failed')
sys.exit (1)
def _get_pxepkg():
#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
_run (['apt-get', 'update'])
acse_gpxe, _ = _run (['apt-cache', 'search', 'gpxe'])
acse_ipxe, _ = _run (['apt-cache', 'search', 'ipxe'])
if acse_ipxe:
pxepkg = 'ipxe'
elif acse_gpxe:
pxepkg = 'gpxe'
else:
logger.error ('neither gpxe nor ipxe found in apt-cache')
pxepkg = None
cache = apt.cache_search (['gpxe', 'ipxe'])
if cache['gpxe']: pxepkg = 'gpxe'
if cache['ipxe']: pxepkg = 'ipxe'
if pxepkg is None:
logger.error ('neither gpxe nor ipxe found in apt cache')
sys.exit (1)
logger.info (f'PXE package is "{pxepkg}"')
return pxepkg
def _mkrootfs():
logger.info ('Fase 3.1 Generar y formatear el disco virtual. Generar el dispositivo loop.')
logger.info ('Stage 3.1 - create, partition and format the rootfs')
rc = subprocess.run (f'file "{btrootfsimg}" |grep -q "partition 1 *: ID=0x83"', shell=True).returncode
print (rc)
if (rc): ## 'file|grep' failed
try: btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch)
try: btog.SetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch)
except Exception as e:
logger.error (str (e))
sys.exit (1)
def _schroot (btrootfsimg):
logger.info ('Fase 3.2 - Configurar acceso schroot al Segundo Sistema de archivos (img)')
btogSetFsAccess (btrootfsimg)
logger.info ('Stage 3.2 - configure schroot in the VM')
btog.SetFsAccess (btrootfsimg)
## para hacer schroot --cosas, el mntpt tiene que estar desmontado
## si está montado da un pete tal que 'E: 10mount: mount: /run/schroot/mount/IMGogclient-7fbf51a2-e37e-48e5-8e5d-83f8901fc7ed: wrong fs type, bad option, bad superblock on /dev/loop1, missing codepage or helper program, or other error.'
def _debootstrap():
logger.info ('Fase 3.3 Generar sistema de archivos con debootstrap')
logger.info ('Stage 3.3 - debootstrap system')
logger.debug ('Try creation of a file within chroot (this operation may fail with "... etc/resolv.conf: No such file or directory"--that is ok)')
logger.debug ('Running \'schroot --chroot IMGogclient -- stat /etc\'')
cp = subprocess.run (['schroot', '--chroot', 'IMGogclient', '--', 'stat', '/etc'])
if (cp.returncode):
logger.debug (f'schroot returned code "{cp.returncode}", calling btogSetFsBase()')
logger.debug (f'schroot returned code "{cp.returncode}", calling btog.SetFsBase()')
_mount_rootfs()
try: btogSetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp)
try: btog.SetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp)
except Exception as e:
logger.error (str (e))
sys.exit (1)
@ -90,76 +87,55 @@ def _debootstrap():
def _initramfs_version (gitrelease, osrelease, btdir):
## FIXME esto la incluye incondicionalmente, y luego terminamos con "OpenGnsys Client 1.2.0-rc1 gitrelease (osrelease) gitrelease (osrelease) gitrelease (osrelease) gitrelease (osrelease) gitrelease (osrelease) gitrelease (osrelease) ..."
#sed -i "1 s/$/ $GITRELEASE ($OSRELEASE)/" ${BTDIR}/includes/etc/initramfs-tools/scripts/VERSION.txt
_run (['sed', '-i', f'1 s/$/ {gitrelease} ({osrelease})/', f'{btdir}/includes/etc/initramfs-tools/scripts/VERSION.txt'])
utils.run (['sed', '-i', f'1 s/$/ {gitrelease} ({osrelease})/', f'{btdir}/includes/etc/initramfs-tools/scripts/VERSION.txt'])
def _copy_files (btrootfsmnt, osdistrib, oscodename):
_mount_rootfs()
builder = '/tmp/opengnsys/oglive_builder'
og_shared = '/tmp/opengnsys/shared'
og_engine = '/tmp/opengnsys/engine'
boottoolsFsOpengnsys (builder, og_shared, og_engine, btrootfsmnt, osdistrib, oscodename)
_umount (btrootfsmnt)
btog.FsOpengnsys (builder, og_shared, og_engine, btrootfsmnt, osdistrib, oscodename)
utils.umount (btrootfsmnt)
def _install_compile_software (curdir, osrelease, osarch):
logger.info ('Fase 5.1 instalar paquetes deb con apt-get')
def _chroot_tasks (curdir, osrelease, osarch):
logger.debug (f'running \'schroot --chroot IMGogclient -- {curdir}/03-boottoolsSoftwareInstall.py --osrelease "{osrelease}" --osarch "{osarch}"\'')
stdout, _ = _run (['schroot', '--chroot', 'IMGogclient', '--', f'{curdir}/03-boottoolsSoftwareInstall.py', '--osrelease', osrelease, '--osarch', osarch])
stdout, _ = utils.run (['schroot', '--chroot', 'IMGogclient', '--', f'{curdir}/03-boottoolsSoftwareInstall.py', '--osrelease', osrelease, '--osarch', osarch])
logger.debug (f'03-boottoolsSoftwareInstall stdout follows:')
for i in stdout.strip().split('\n'): logger.debug (' ' + i)
logger.info ('Fase 5.2 compilar software.')
logger.debug (f'running \'schroot --chroot IMGogclient -- {curdir}/04-boottoolsSoftwareCompile.py\'')
stdout, _ = _run (['schroot', '--chroot', 'IMGogclient', '--', f'{curdir}/04-boottoolsSoftwareCompile.py'])
logger.debug (f'04-boottoolsSoftwareCompile stdout follows:')
for i in stdout.strip().split('\n'): logger.debug (' ' + i)
def _debconf2 (curdir):
logger.info ('Fase 6.1 Configurar las locales')
logger.debug (f'running \'schroot --chroot IMGogclient -- {curdir}/05-boottoolsFsLocales.py\'')
stdout, _ = _run (['schroot', '--chroot', 'IMGogclient', '--', f'{curdir}/05-boottoolsFsLocales.py'])
logger.debug (f'05-boottoolsFsLocales stdout follows:')
for i in stdout.strip().split('\n'): logger.debug (' ' + i)
logger.info ('Fase 6.3 Crear initrd')
logger.debug (f'running \'schroot --chroot IMGogclient -- {curdir}/06-boottoolsInitrdGenerate.py --osrelease "{osrelease}"\'')
stdout, _ = _run (['schroot', '--chroot', 'IMGogclient', '--', f'{curdir}/06-boottoolsInitrdGenerate.py', '--osrelease', osrelease])
logger.debug (f'06-boottoolsInitrdGenerate stdout follows:')
for i in stdout.strip().split('\n'): logger.debug (' ' + i)
## esto deja initrd.img-6.8.0-31-generic y vmlinuz-6.8.0-31-generic en /tmp
for i in stdout.strip().split ('\n'): logger.debug (' ' + i)
def _ssh_stuff():
logger.info ('Fase 6.2 Configurar ssh')
_mount_rootfs()
boottoolsSshServer (btrootfsmnt)
boottoolsSshClient (btrootfsmnt)
_umount (btrootfsmnt)
btog.SshServer (btrootfsmnt)
btog.SshClient (btrootfsmnt)
utils.umount (btrootfsmnt)
## el resultado es:
## - hay un nuevo par de claves en la VM /root/.ssh
## - hay otro nuevo par de claves en el rootfs /var/lib/tftpboot/ogclient/ogclientmount/root/.ssh
## - las dos claves públicas (una de cada par) están autorizadan en el rootfs /var/lib/tftpboot/ogclient/ogclientmount/root/.ssh/authorized_keys
def _mkinitrd_squashfs_isofs (bttargetdir, osrelease, btrootfsmnt, pxepkg, isolinux_tpl nameisoclient):
logger.info ('Fase 7.1 Copiar el initrd a su sitio')
def _mkinitrd_squashfs_isofs (bttargetdir, osrelease, btrootfsmnt, pxepkg, isolinux_tpl, nameisoclient):
logger.info ('Stage 6.1 - Put initrd in place')
_mount_rootfs()
btogFsInitrd (bttargetdir, osrelease)
btog.FsInitrd (bttargetdir, osrelease)
logger.info ('Fase 7.2 Generar fichero sqfs a partir del fichero img')
btogFsSqfs (bttargetdir, btrootfsmnt)
_umount (btrootfsmnt)
logger.info ('Stage 6.2 - make squash filesystem')
btog.FsSqfs (bttargetdir, btrootfsmnt)
utils.umount (btrootfsmnt)
logger.info ('Fase 7.3 Generar la ISO')
btogIsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient)
logger.info ('Stage 6.3 - make iso filesystem')
btog.IsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient)
config = _read_config ('boottoolsgenerator.cfg')
config = utils.read_config ('boottoolsgenerator.cfg')
if config is None:
sys.exit (1)
isolinux_tpl = config['General'].get ('isolinux_template')
lvl = config['General'].get ('logging_level')
logger = _logging()
type_client = sys.argv[1] if len(sys.argv)>1 else 'host'
type_client = sys.argv[1] if len (sys.argv)>1 else 'host'
if os.getuid():
logger.error ('ERROR: this program must run under root privileges!!')
@ -167,44 +143,44 @@ if os.getuid():
#os.chdir ('/tmp')
## this is convenient in case the previous run failed and we want to run this program again
try: utils.umount (btrootfsmnt)
except: pass
logger.info ('OpenGnsys CLIENT installation begins')
logger.info ('STAGE 1 - clone opengnsys repo')
ogrepo_url = 'https://ognproject.evlt.uma.es/gitea/opengnsys/opengnsys.git'
ogrepo_branch = 'main'
ogrepo_dir = '/tmp/ogrepo'
clone_client_dirs (ogrepo_url, ogrepo_branch, ogrepo_dir)
logger.info ('FASE 1 - Asignación de variables')
osdistrib, oscodename, osrelease, osarch, oshttp = btogGetOsInfo1(type_client)
btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize = btogGetVar(osarch)
gitrelease, nameisoclient, namehostclient = btogGetOsInfo2(ogrepo_dir, versionboottools, oscodename, osrelease, osarch)
osdistrib, oscodename, osrelease, osarch, oshttp = btog.GetOsInfo1 (type_client)
btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize = btog.GetVar (osarch)
gitrelease, nameisoclient, namehostclient = btog.GetOsInfo2 (ogrepo_dir, versionboottools, oscodename, osrelease, osarch)
logger.info (':'.join ([osdistrib, oscodename, osrelease, osarch, oshttp]))
## this is convenient in case the previous run failed and we want to run this program again
try: _umount (btrootfsmnt)
except: pass
logger.info ('FASE 2 - Instalación de software adicional.')
logger.info ('STAGE 2 - install software in the VM')
apt.update()
apt.upgrade()
pxepkg = _get_pxepkg()
_run (['apt-get', '-y', 'install', 'jq', 'syslinux', 'syslinux-efi', 'syslinux-utils', 'debootstrap', 'subversion', 'schroot', 'squashfs-tools', 'syslinux', 'genisoimage', 'qemu-utils', 'lsof', pxepkg]) ## TODO qemu no existe, hace falta?
apt.install (['jq', 'syslinux', 'syslinux-efi', 'syslinux-utils', 'debootstrap', 'subversion', 'schroot', 'squashfs-tools', 'syslinux', 'genisoimage', 'qemu-utils', 'lsof', pxepkg]) ## TODO qemu no existe, hace falta?
logger.info ('FASE 3 - Creación del Sistema raiz RootFS (Segundo Sistema archivos (img))')
logger.info ('STAGE 3 - create and bootstrap rootfs')
_mkrootfs()
_schroot (btrootfsimg)
_debootstrap()
logger.info ('FASE 4 - Incorporando ficheros OpenGnsys al sistema raíz rootfs')
logger.info ('STAGE 4 - copy files to the rootfs')
_initramfs_version (gitrelease, osrelease, btdir)
_copy_files (btrootfsmnt, osdistrib, oscodename, osrelease, osarch, oshttp)
_copy_files (btrootfsmnt, osdistrib, oscodename)
logger.info ('FASE 5 - Instalar software')
_install_compile_software (curdir, osrelease, osarch)
logger.info ('STAGE 5 - perform tasks within the chroot')
_chroot_tasks (curdir, osrelease, osarch)
logger.info ('FASE 6 - Personalizar el sistema creado')
_debconf2 (curdir)
_ssh_stuff()
logger.info ('FASE 7 - Generar distribucion')
_mkinitrd_squashfs_isofs (bttargetdir, osrelease, btrootfsmnt, pxepkg, isolinux_tpl nameisoclient)
logger.info ('STAGE 6 - generate distribution files')
_mkinitrd_squashfs_isofs (bttargetdir, osrelease, btrootfsmnt, pxepkg, isolinux_tpl, nameisoclient)
logger.info ('OpenGnsys installation finished')