from os import remove as rmfile
from os.path import isdir, isfile, join as joinpath, basename, abspath, expanduser
+import os
import math
import json
import tarfile
-import time
import shutil
import subprocess
+import textwrap
from .common import FDroidException
from logging import getLogger
+from fdroidserver import _
+
logger = getLogger('fdroidserver-vmtools')
+def get_clean_builder(serverdir, reset=False):
+ if not os.path.isdir(serverdir):
+ if os.path.islink(serverdir):
+ os.unlink(serverdir)
+ logger.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 = get_build_vm(serverdir)
+ if reset:
+ logger.info('resetting buildserver by request')
+ elif not vm.vagrant_uuid_okay():
+ logger.info('resetting buildserver, bceause vagrant vm is not okay.')
+ reset = True
+ elif not vm.snapshot_exists('fdroidclean'):
+ logger.info("resetting buildserver, because snapshot 'fdroidclean' is not present.")
+ reset = True
+
+ if reset:
+ vm.destroy()
+ vm.up()
+ vm.suspend()
+
+ if reset:
+ logger.info('buildserver recreated: taking a clean snapshot')
+ vm.snapshot_create('fdroidclean')
+ else:
+ logger.info('builserver ok: reverting to clean snapshot')
+ vm.snapshot_revert('fdroidclean')
+ vm.up()
+
+ try:
+ sshinfo = vm.sshinfo()
+ except FDroidBuildVmException:
+ # workaround because libvirt sometimes likes to forget
+ # about ssh connection info even thou the vm is running
+ vm.halt()
+ vm.up()
+ sshinfo = vm.sshinfo()
+
+ return sshinfo
+
+
def _check_call(cmd, shell=False, cwd=None):
logger.debug(' '.join(cmd))
return subprocess.check_call(cmd, shell=shell, cwd=cwd)
has_libvirt_machine = isdir(joinpath(abssrvdir, '.vagrant',
'machines', 'default', 'libvirt'))
has_vbox_machine = isdir(joinpath(abssrvdir, '.vagrant',
- 'machines', 'default', 'libvirt'))
+ 'machines', 'default', 'virtualbox'))
if has_libvirt_machine and has_vbox_machine:
logger.info('build vm provider lookup found virtualbox and libvirt, defaulting to \'virtualbox\'')
return VirtualboxBuildVm(abssrvdir)
def up(self, provision=True):
try:
self.vgrnt.up(provision=provision)
- logger.info('...waiting a sec...')
- time.sleep(10)
self.srvuuid = self._vagrant_fetch_uuid()
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not bring up vm '%s'" % self.srvname) from e
logger.info('suspending buildserver')
try:
self.vgrnt.suspend()
- logger.info('...waiting a sec...')
- time.sleep(10)
except subprocess.CalledProcessError as e:
raise FDroidBuildVmException("could not suspend vm '%s'" % self.srvname) from e
except subprocess.CalledProcessError as e:
logger.debug('pruning global vagrant status failed: %s', e)
- def package(self, output=None, vagrantfile=None, keep_box_file=None):
- self.vgrnt.package(output=output, vagrantfile=vagrantfile)
+ def package(self, output=None):
+ self.vgrnt.package(output=output)
def vagrant_uuid_okay(self):
'''Having an uuid means that vagrant up has run successfully.'''
# (eg. lookupByName only works on running VMs)
try:
_check_call(('virsh', '-c', 'qemu:///system', 'destroy', self.srvname))
- logger.info("...waiting a sec...")
- time.sleep(10)
except subprocess.CalledProcessError as e:
logger.info("could not force libvirt domain '%s' off: %s", self.srvname, e)
try:
# libvirt python bindings do not support all flags required
# for undefining domains correctly.
_check_call(('virsh', '-c', 'qemu:///system', 'undefine', self.srvname, '--nvram', '--managed-save', '--remove-all-storage', '--snapshots-metadata'))
- logger.info("...waiting a sec...")
- time.sleep(10)
except subprocess.CalledProcessError as e:
logger.info("could not undefine libvirt domain '%s': %s", self.srvname, e)
- def package(self, output=None, vagrantfile=None, keep_box_file=False):
+ def package(self, output=None, keep_box_file=False):
if not output:
output = "buildserver.box"
logger.debug('no output name set for packaging \'%s\',' +
'defaulting to %s', self.srvname, output)
storagePool = self.conn.storagePoolLookupByName('default')
+ domainInfo = self.conn.lookupByName(self.srvname).info()
if storagePool:
if isfile('metadata.json'):
vol = storagePool.storageVolLookupByName(self.srvname + '.img')
imagepath = vol.path()
# TODO use a libvirt storage pool to ensure the img file is readable
- _check_call(['sudo', '/bin/chmod', '-R', 'a+rX', '/var/lib/libvirt/images'])
+ if not os.access(imagepath, os.R_OK):
+ logger.warning(_('Cannot read "{path}"!').format(path=imagepath))
+ _check_call(['sudo', '/bin/chmod', '-R', 'a+rX', '/var/lib/libvirt/images'])
shutil.copy2(imagepath, 'box.img')
_check_call(['qemu-img', 'rebase', '-p', '-b', '', 'box.img'])
img_info_raw = _check_output(['qemu-img', 'info', '--output=json', 'box.img'])
"virtual_size": math.ceil(img_info['virtual-size'] / (1024. ** 3)),
}
- if not vagrantfile:
- logger.debug('no Vagrantfile supplied for box, generating a minimal one...')
- vagrantfile = 'Vagrant.configure("2") do |config|\nend'
-
logger.debug('preparing metadata.json for box %s', output)
with open('metadata.json', 'w') as fp:
fp.write(json.dumps(metadata))
logger.debug('preparing Vagrantfile for box %s', output)
+ vagrantfile = textwrap.dedent("""\
+ Vagrant.configure("2") do |config|
+ config.ssh.username = "vagrant"
+ config.ssh.password = "vagrant"
+
+ config.vm.provider :libvirt do |libvirt|
+
+ libvirt.driver = "kvm"
+ libvirt.host = ""
+ libvirt.connect_via_ssh = false
+ libvirt.storage_pool_name = "default"
+ libvirt.cpus = {cpus}
+ libvirt.memory = {memory}
+
+ end
+ end""".format_map({'memory': str(int(domainInfo[1] / 1024)), 'cpus': str(domainInfo[3])}))
with open('Vagrantfile', 'w') as fp:
fp.write(vagrantfile)
with tarfile.open(output, 'w:gz') as tar:
logger.info("creating snapshot '%s' for vm '%s'", snapshot_name, self.srvname)
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'"
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
logger.info("creating snapshot '%s' for vm '%s'", snapshot_name, self.srvname)
try:
_check_call(['VBoxManage', 'snapshot', self.srvuuid, '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'