314 lines
14 KiB
Python
314 lines
14 KiB
Python
|
|
import platform
|
|
import os
|
|
import re
|
|
import time
|
|
import logging
|
|
import subprocess
|
|
import shutil
|
|
import glob
|
|
|
|
logger = logging.getLogger ('boottools')
|
|
|
|
def btogGetVar (osarch):
|
|
btdir = '/tmp/opengnsys_installer/opengnsys/client/boot-tools'
|
|
bttargetdir = '/var/lib/tftpboot/ogclient/'
|
|
btrootfsimg = os.path.join (bttargetdir, 'ogclient.img')
|
|
btrootfsmnt = os.path.join (bttargetdir, 'ogclientmount')
|
|
btrootfsimglabel = 'ogClient'
|
|
log_file = '/tmp/boot-tools_installation.log'
|
|
versionboottools = 'ogLive'
|
|
if 'i386' == osarch:
|
|
btvirtualdisksize = '2000' # tamaño maximo limitado por schroot 2GB para 32 bits
|
|
else:
|
|
btvirtualdisksize = '3G'
|
|
return btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize
|
|
|
|
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'
|
|
oscodename='precise'
|
|
osrelease='3.2.0-23-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'wheezy' == type_client: # ogLive basado en Debian 7.3.
|
|
osdistrib='debian'
|
|
oscodename='wheezy'
|
|
osrelease='3.2.0-4-i386'
|
|
osarch='i386'
|
|
oshttp='http://ftp.es.debian.org/debian/'
|
|
elif 'quantal' == type_client: # ogLive 1.0.5-rc2 basado en Ubuntu 12.10 con Kernel descargado.
|
|
osdistrib='ubuntu'
|
|
oscodename='quantal'
|
|
osrelease='3.7.6-030706-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'raring' == type_client: # ogLive 1.0.5-rc3 basado en Ubuntu 13.04.
|
|
osdistrib='ubuntu'
|
|
oscodename='raring'
|
|
osrelease='3.8.0-22-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'trusty' == type_client: # ogLive 1.0.5-rc4 basado en Ubuntu 14.04.
|
|
osdistrib='ubuntu'
|
|
oscodename='trusty'
|
|
osrelease='3.13.0-24-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'vivid' == type_client: # ogLive 1.1.0-rc2 basado en Ubuntu 15.04.
|
|
osdistrib='ubuntu'
|
|
oscodename='vivid'
|
|
osrelease='3.19.0-49-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'wily' == type_client: # ogLive 1.1.0-rc1 basado en Ubuntu 15.10.
|
|
osdistrib='ubuntu'
|
|
oscodename='wily'
|
|
osrelease='4.2.0-35-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'xenial' == type_client or 'xenial-4.4' == type_client: # ogLive 1.1.0-rc4 basado en Ubuntu 16.04 y Kernel 4.4.
|
|
osdistrib='ubuntu'
|
|
oscodename='xenial'
|
|
osrelease='4.4.0-34-generic'
|
|
osarch='i386'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'xenial-4.8' == type_client: # ogLive 1.1.0-rc5 basado en Ubuntu 16.04 y Kernel 4.8.
|
|
osdistrib='ubuntu'
|
|
oscodename='xenial'
|
|
osrelease='4.8.0-39-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'xenial-4.13' == type_client: # ogLive 1.1.0-rc6 basado en Ubuntu 16.04 y Kernel 4.13.
|
|
osdistrib='ubuntu'
|
|
oscodename='xenial'
|
|
osrelease='4.13.0-17-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'bionic' == type_client or 'bionic-4.15' == type_client: # ogLive 1.1.1-rc1 basado en Ubuntu 18.04 y Kernel 4.15.
|
|
osdistrib='ubuntu'
|
|
oscodename='bionic'
|
|
osrelease='4.15.0-32-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'bionic-4.18' == type_client: # ogLive 1.1.1-rc3 basado en Ubuntu 18.04 y Kernel 4.18.
|
|
osdistrib='ubuntu'
|
|
oscodename='bionic'
|
|
osrelease='4.18.0-20-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'bionic-5.0' == type_client: # ogLive 1.1.1-rc5 basado en Ubuntu 18.04 y Kernel 5.0.
|
|
osdistrib='ubuntu'
|
|
oscodename='bionic'
|
|
osrelease='5.0.0-27-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'focal' == type_client: # ogLive 1.2.0-rc1 basado en Ubuntu 20.04 y Kernel 5.4.
|
|
osdistrib='ubuntu'
|
|
oscodename='focal'
|
|
osrelease='5.4.0-42-generic'
|
|
osarch='amd64'
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
elif 'host' == type_client: # ogLive basado en la distribución del servidor.
|
|
osdistrib=platform.freedesktop_os_release()['NAME']
|
|
oscodename=platform.freedesktop_os_release()['VERSION_CODENAME']
|
|
osrelease=platform.uname()[2]
|
|
osarch=subprocess.run (['dpkg', '--print-architecture'], capture_output=True).stdout.decode ('utf-8').strip()
|
|
oshttp='http://es.archive.ubuntu.com/ubuntu/'
|
|
else: # Parámetro desconocido
|
|
print ('Parámetro no válido.')
|
|
os.exit (1)
|
|
return 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])')
|
|
nameisoclient ='-'.join ([versionboottools, oscodename, osrelease, osarch, gitrelease])
|
|
namehostclient = '-'.join ([versionboottools, oscodename, gitrelease])
|
|
|
|
### El fichero de configuración debe sustituir a estos 3 ficheros (borrar las 3 líneas siguientes).
|
|
#echo "$NAMEISOCLIENT" > /tmp/opengnsys_info_rootfs
|
|
#echo "$NAMEHOSTCLIENT" > /tmp/opengnsys_chroot
|
|
|
|
# Generar fichero de configuración.
|
|
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)
|
|
print ('OSRELEASE="{}"'.format (osrelease), file=f)
|
|
print ('OSARCH="{}"'.format (osarch), file=f)
|
|
print ('OSHTTP="{}"'.format (oshttp), file=f)
|
|
print ('GITRELEASE="{}"'.format (gitrelease, file=f))
|
|
print ('NAMEISOCLIENT="{}"'.format (nameisoclient), file=f)
|
|
print ('NAMEHOSTCLIENT="{}"'.format (namehostclient), file=f)
|
|
|
|
return gitrelease, nameisoclient, namehostclient
|
|
|
|
def _run (args):
|
|
cp = subprocess.run (args, capture_output=True)
|
|
if cp.returncode:
|
|
logger.error ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode))
|
|
raise
|
|
stdout = cp.stdout.decode ('utf-8').strip()
|
|
stderr = cp.stderr.decode ('utf-8').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 _umount (mntpt):
|
|
if (_is_mounted (mntpt)):
|
|
subprocess.run (['umount', mntpt])
|
|
|
|
def btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch):
|
|
#if not btrootfsimg: btogGetVar()
|
|
|
|
logger.info ('Creación y formateo del disco virtual "{}" "{}" MB'.format (btrootfsimg, btvirtualdisksize))
|
|
|
|
try: _umount (btrootfsmnt)
|
|
except: pass
|
|
|
|
if (_is_mounted (btrootfsmnt)):
|
|
raise Exception ('failed to umount "{}"'.format (btrootfsmnt))
|
|
|
|
try: os.makedirs (btrootfsmnt, exist_ok=True)
|
|
except:
|
|
raise Exception ('Creando directorio "{}" : ERROR'.format (btrootfsmnt))
|
|
|
|
try: _run (['chown', '-R', 'root:opengnsys', bttargetdir])
|
|
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:
|
|
raise Exception ('Creando el disco virtual "{}" con tamaño maxima "{}" MB : ERROR'.format (btrootfsimg, btvirtualdisksize))
|
|
else:
|
|
try: _run (['qemu-img', 'create', btrootfsimg, btvirtualdisksize])
|
|
except:
|
|
raise Exception ('Creando el disco virtual "{}" con tamaño maxima "{}" MB : ERROR'.format (btrootfsimg, btvirtualdisksize))
|
|
|
|
logger.debug ('losetup --find')
|
|
diskloop, _ = _run (['losetup', '--find'])
|
|
if not diskloop:
|
|
raise Exception ('no diskloop')
|
|
|
|
logger.debug ('losetup attach')
|
|
try: _run (['losetup', diskloop, btrootfsimg])
|
|
except: raise Exception ('losetup failed')
|
|
|
|
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 (5)
|
|
logger.debug ('losetup --detach')
|
|
try: _run (['losetup', '--detache', diskloop])
|
|
except:
|
|
raise Exception ('Liberando disco virtual despues del particionado: ERROR')
|
|
|
|
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:
|
|
raise Exception ('Formateando la particion principal del disco virtual: ERROR')
|
|
|
|
time.sleep (5)
|
|
logger.debug ('losetup --detach')
|
|
try: _run (['losetup', '--detach', partloop])
|
|
except:
|
|
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 system> <mount point> <type> <options> <dump> <pass>', 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
|