1
0
mirror of https://gitlab.com/fdroid/fdroidserver.git synced 2024-11-20 13:50:12 +01:00

revised build server creation

This commit is contained in:
Michael Pöhn 2017-04-06 11:42:35 +02:00 committed by Hans-Christoph Steiner
parent 8abd3f1cbc
commit 3187d2cbcf
2 changed files with 133 additions and 12 deletions

View File

@ -29,6 +29,7 @@ import time
import json import json
import requests import requests
import tempfile import tempfile
import textwrap
from configparser import ConfigParser from configparser import ConfigParser
from argparse import ArgumentParser from argparse import ArgumentParser
import logging import logging
@ -223,6 +224,45 @@ def vm_test_ssh_into_builder():
sshs.close() sshs.close()
def vm_new_get_clean_builder(serverdir, reset=False):
if not os.path.isdir(serverdir):
logging.info("buildserver path does not exists, creating %s", serverdir)
os.makedirs(serverdir)
vagrantfile = os.path.join(serverdir, 'Vagrantfile')
if not os.path.isfile(vagrantfile):
with open(os.path.join('builder', 'Vagrantfile'), 'w') as f:
f.write(textwrap.dedent("""\
# generated file, do not change.
Vagrant.configure("2") do |config|
config.vm.box = "buildserver"
config.vm.synced_folder ".", "/vagrant", disabled: true
end
"""))
vm = vmtools.get_build_vm(serverdir)
if reset:
logging.info('resetting buildserver by request')
elif not vm.check_okay():
logging.info('resetting buildserver because it appears to be absent or broken')
reset = True
elif not vm.snapshot_exists('fdroidclean'):
logging.info("resetting buildserver, because snapshot 'fdroidclean' is not present")
reset = True
if reset:
vm.destroy()
vm.up()
vm.suspend()
if reset:
vm.snapshot_create('fdroidclean')
else:
vm.snapshot_revert('droidclean')
vm.resume()
return get_vagrant_sshinfo()
def vm_get_clean_builder(reset=False): def vm_get_clean_builder(reset=False):
"""Get a clean VM ready to do a buildserver build. """Get a clean VM ready to do a buildserver build.
@ -374,7 +414,8 @@ def build_server(app, build, vcs, build_dir, output_dir, log_dir, force):
else: else:
logging.getLogger("paramiko").setLevel(logging.WARN) logging.getLogger("paramiko").setLevel(logging.WARN)
sshinfo = vm_get_clean_builder() # sshinfo = vm_get_clean_builder()
sshinfo = vm_new_get_clean_builder('builder')
try: try:
if not buildserverid: if not buildserverid:

View File

@ -17,13 +17,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from os import remove as rmfile from os import remove as rmfile
from os.path import isdir, isfile, join as joinpath, basename, abspath from os.path import isdir, isfile, join as joinpath, basename, abspath, expanduser
import math import math
import json import json
import tarfile import tarfile
import time import time
import shutil import shutil
import vagrant
import subprocess import subprocess
from .common import FDroidException from .common import FDroidException
from logging import getLogger from logging import getLogger
@ -132,10 +131,11 @@ class FDroidBuildVm():
raise FDroidBuildVmException("Can not init vagrant, directory %s not present" % (srvdir)) raise FDroidBuildVmException("Can not init vagrant, directory %s not present" % (srvdir))
if not isfile(self.vgrntfile): if not isfile(self.vgrntfile):
raise FDroidBuildVmException("Can not init vagrant, '%s' not present" % (self.vgrntfile)) raise FDroidBuildVmException("Can not init vagrant, '%s' not present" % (self.vgrntfile))
import vagrant
self.vgrnt = vagrant.Vagrant(root=srvdir, out_cm=vagrant.stdout_cm, err_cm=vagrant.stdout_cm) self.vgrnt = vagrant.Vagrant(root=srvdir, out_cm=vagrant.stdout_cm, err_cm=vagrant.stdout_cm)
def isUpAndRunning(self): def check_okay(self):
raise NotImplementedError('TODO implement this') return True
def up(self, provision=True): def up(self, provision=True):
try: try:
@ -143,6 +143,15 @@ class FDroidBuildVm():
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
logger.info('could not bring vm up: %s', e) logger.info('could not bring vm up: %s', e)
def snapshot_create(self, name):
raise NotImplementedError('not implemented, please use a sub-type instance')
def suspend(self):
self.vgrnt.suspend()
def resume(self):
self.vgrnt.resume()
def halt(self): def halt(self):
self.vgrnt.halt(force=True) self.vgrnt.halt(force=True)
@ -177,6 +186,9 @@ class FDroidBuildVm():
shutil.rmtree(previous_tmp_dir) shutil.rmtree(previous_tmp_dir)
self.vgrnt.package(output=output, vagrantfile=vagrantfile) self.vgrnt.package(output=output, vagrantfile=vagrantfile)
def _vagrant_file_name(self, name):
return name.replace('/', '-VAGRANTSLASH-')
def box_add(self, boxname, boxfile, force=True): def box_add(self, boxname, boxfile, force=True):
"""Add vagrant box to vagrant. """Add vagrant box to vagrant.
@ -194,8 +206,12 @@ class FDroidBuildVm():
_check_call(['vagrant', 'box', 'remove', '--all', '--force', boxname]) _check_call(['vagrant', 'box', 'remove', '--all', '--force', boxname])
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
logger.debug('tried removing box %s, but is did not exist: %s', boxname, e) logger.debug('tried removing box %s, but is did not exist: %s', boxname, e)
# TODO: remove box files manually boxpath = joinpath(expanduser('~'), '.vagrant',
# nesessary when Vagrantfile in ~/.vagrant.d/... is broken. self._vagrant_file_name(boxname))
if isdir(boxpath):
logger.info("attempting to remove box '%s' by deleting: %s",
boxname, boxpath)
shutil.rmtree(boxpath)
class LibvirtBuildVm(FDroidBuildVm): class LibvirtBuildVm(FDroidBuildVm):
@ -208,6 +224,22 @@ class LibvirtBuildVm(FDroidBuildVm):
except libvirt.libvirtError as e: except libvirt.libvirtError as e:
raise FDroidBuildVmException('could not connect to libvirtd: %s' % (e)) raise FDroidBuildVmException('could not connect to libvirtd: %s' % (e))
def check_okay(self):
import libvirt
imagepath = joinpath('var', 'lib', 'libvirt', 'images',
'%s.img' % self._vagrant_file_name(self.srvname))
image_present = False
if isfile(imagepath):
image_present = True
try:
self.conn.lookupByName(self.srvname)
domain_defined = True
except libvirt.libvirtError:
pass
if image_present and domain_defined:
return True
return False
def destroy(self): def destroy(self):
super().destroy() super().destroy()
@ -235,9 +267,7 @@ class LibvirtBuildVm(FDroidBuildVm):
output = "buildserver.box" output = "buildserver.box"
logger.debug('no output name set for packaging \'%s\',' + logger.debug('no output name set for packaging \'%s\',' +
'defaulting to %s', self.srvname, output) 'defaulting to %s', self.srvname, output)
import libvirt storagePool = self.conn.storagePoolLookupByName('default')
virConnect = libvirt.open('qemu:///system')
storagePool = virConnect.storagePoolLookupByName('default')
if storagePool: if storagePool:
if isfile('metadata.json'): if isfile('metadata.json'):
@ -258,7 +288,7 @@ class LibvirtBuildVm(FDroidBuildVm):
img_info = json.loads(img_info_raw.decode('utf-8')) img_info = json.loads(img_info_raw.decode('utf-8'))
metadata = {"provider": "libvirt", metadata = {"provider": "libvirt",
"format": img_info['format'], "format": img_info['format'],
"virtual_size": math.ceil(img_info['virtual-size'] / (1024. ** 3)) + 1, "virtual_size": math.ceil(img_info['virtual-size'] / (1024. ** 3)),
} }
if not vagrantfile: if not vagrantfile:
@ -296,6 +326,56 @@ class LibvirtBuildVm(FDroidBuildVm):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
logger.info('tired removing \'%s\', file was not present in first place: %s', boxname, e) logger.info('tired removing \'%s\', file was not present in first place: %s', boxname, e)
def snapshot_create(self, snapshot_name):
try:
_check_call(['virsh', '-c', 'qemu:///system', 'snapshot-create-as', self.srvname, snapshot_name])
logger.info('...waiting a sec...')
time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not cerate snapshot '%s' "
"of libvirt vm '%s'"
% (snapshot_name, self.srvname)) from e
def snapshot_list(self):
import libvirt
try:
dom = self.conn.lookupByName(self.srvname)
return dom.listAllSnapshots()
except libvirt.libvirtError as e:
raise FDroidBuildVmException('could not list snapshots for domain \'%s\'' % self.srvname) from e
def snapshot_exists(self, snapshot_name):
import libvirt
try:
dom = self.conn.lookupByName(self.srvname)
return dom.snapshotLookupByName(snapshot_name) is not None
except libvirt.libvirtError:
return False
def snapshot_revert(self, snapshot_name):
import libvirt
try:
dom = self.conn.lookupByName(self.srvname)
snap = dom.snapshotLookupByName(snapshot_name)
dom.revertToSnapshot(snap)
logger.info('...waiting a sec...')
time.sleep(10)
except libvirt.libvirtError as e:
raise FDroidBuildVmException('could not revert domain \'%s\' to snapshot \'%s\''
% (self.srvname, snapshot_name)) from e
class VirtualboxBuildVm(FDroidBuildVm): class VirtualboxBuildVm(FDroidBuildVm):
pass def snapshot_create(self, snapshot_name):
raise NotImplemented('TODO')
try:
_check_call(['VBoxManage', 'snapshot', self.srvname, 'take', 'fdroidclean'], cwd=self.srvdir)
logger.info('...waiting a sec...')
time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException('could not cerate snapshot '
'of virtualbox vm %s'
% self.srvname) from e
def snapshot_available(self, snapshot_name):
raise NotImplemented('TODO')