# along with this program. If not, see <http://www.gnu.org/licenses/>.
from os import remove as rmfile
-from os.path import isdir, isfile, join as joinpath, basename, abspath, expanduser
+from os.path import isdir, isfile, 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 _
+import threading
+
+lock = threading.Lock()
+
logger = getLogger('fdroidserver-vmtools')
if reset:
logger.info('resetting buildserver by request')
elif not vm.vagrant_uuid_okay():
- logger.info('resetting buildserver, bceause vagrant vm is not okay.')
+ logger.info('resetting buildserver, because vagrant vm is not okay.')
reset = True
elif not vm.snapshot_exists('fdroidclean'):
logger.info("resetting buildserver, because snapshot 'fdroidclean' is not present.")
return sshinfo
-def _check_call(cmd, shell=False, cwd=None):
+def _check_call(cmd, cwd=None):
logger.debug(' '.join(cmd))
- return subprocess.check_call(cmd, shell=shell, cwd=cwd)
+ return subprocess.check_call(cmd, shell=False, cwd=cwd)
-def _check_output(cmd, shell=False, cwd=None):
+def _check_output(cmd, cwd=None):
logger.debug(' '.join(cmd))
- return subprocess.check_output(cmd, shell=shell, cwd=cwd)
+ return subprocess.check_output(cmd, shell=False, cwd=cwd)
def get_build_vm(srvdir, provider=None):
logger.debug('could not confirm that either virtualbox or kvm/libvirt are installed')
# try guessing provider from .../srvdir/.vagrant internals
- has_libvirt_machine = isdir(joinpath(abssrvdir, '.vagrant',
- 'machines', 'default', 'libvirt'))
- has_vbox_machine = isdir(joinpath(abssrvdir, '.vagrant',
- 'machines', 'default', 'libvirt'))
+ has_libvirt_machine = isdir(os.path.join(abssrvdir, '.vagrant',
+ 'machines', 'default', 'libvirt'))
+ has_vbox_machine = isdir(os.path.join(abssrvdir, '.vagrant',
+ '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)
This is intended to be a hypervisor independant, fault tolerant
wrapper around the vagrant functions we use.
"""
-
def __init__(self, srvdir):
"""Create new server class.
"""
self.srvdir = srvdir
self.srvname = basename(srvdir) + '_default'
- self.vgrntfile = joinpath(srvdir, 'Vagrantfile')
+ self.vgrntfile = os.path.join(srvdir, 'Vagrantfile')
self.srvuuid = self._vagrant_fetch_uuid()
if not isdir(srvdir):
raise FDroidBuildVmException("Can not init vagrant, directory %s not present" % (srvdir))
self.vgrnt = vagrant.Vagrant(root=srvdir, out_cm=vagrant.stdout_cm, err_cm=vagrant.stdout_cm)
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
+ global lock
+ with lock:
+ try:
+ self.vgrnt.up(provision=provision)
+ self.srvuuid = self._vagrant_fetch_uuid()
+ except subprocess.CalledProcessError as e:
+ raise FDroidBuildVmException("could not bring up vm '%s'" % self.srvname) from e
def suspend(self):
- 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
+ global lock
+ with lock:
+ logger.info('suspending buildserver')
+ try:
+ self.vgrnt.suspend()
+ except subprocess.CalledProcessError as e:
+ raise FDroidBuildVmException("could not suspend vm '%s'" % self.srvname) from e
def halt(self):
- self.vgrnt.halt(force=True)
+ global lock
+ with lock:
+ self.vgrnt.halt(force=True)
def destroy(self):
"""Remove every trace of this VM from the system.
logger.debug('vagrant destroy completed')
except subprocess.CalledProcessError as e:
logger.exception('vagrant destroy failed: %s', e)
- vgrntdir = joinpath(self.srvdir, '.vagrant')
+ vgrntdir = os.path.join(self.srvdir, '.vagrant')
try:
shutil.rmtree(vgrntdir)
logger.debug('deleted vagrant dir: %s', vgrntdir)
return name.replace('/', '-VAGRANTSLASH-')
def _vagrant_fetch_uuid(self):
- if isfile(joinpath(self.srvdir, '.vagrant')):
+ if isfile(os.path.join(self.srvdir, '.vagrant')):
# Vagrant 1.0 - it's a json file...
- with open(joinpath(self.srvdir, '.vagrant')) as f:
+ with open(os.path.join(self.srvdir, '.vagrant')) as f:
id = json.load(f)['active']['default']
logger.debug('vm uuid: %s', id)
return id
- elif isfile(joinpath(self.srvdir, '.vagrant', 'machines',
- 'default', self.provider, 'id')):
+ elif isfile(os.path.join(self.srvdir, '.vagrant', 'machines',
+ 'default', self.provider, 'id')):
# Vagrant 1.2 (and maybe 1.1?) it's a directory tree...
- with open(joinpath(self.srvdir, '.vagrant', 'machines',
- 'default', self.provider, 'id')) as f:
+ with open(os.path.join(self.srvdir, '.vagrant', 'machines',
+ 'default', self.provider, 'id')) as f:
id = f.read()
logger.debug('vm uuid: %s', id)
return id
_check_call(['vagrant', 'box', 'remove', '--all', '--force', boxname])
except subprocess.CalledProcessError as e:
logger.debug('tried removing box %s, but is did not exist: %s', boxname, e)
- boxpath = joinpath(expanduser('~'), '.vagrant',
- self._vagrant_file_name(boxname))
+ boxpath = os.path.join(expanduser('~'), '.vagrant',
+ self._vagrant_file_name(boxname))
if isdir(boxpath):
logger.info("attempting to remove box '%s' by deleting: %s",
boxname, boxpath)
"""
import paramiko
try:
- _check_call(['vagrant ssh-config > sshconfig'],
- cwd=self.srvdir, shell=True)
+ sshconfig_path = os.path.join(self.srvdir, 'sshconfig')
+ with open(sshconfig_path, 'wb') as fp:
+ fp.write(_check_output(['vagrant', 'ssh-config'],
+ cwd=self.srvdir))
vagranthost = 'default' # Host in ssh config file
sshconfig = paramiko.SSHConfig()
- with open(joinpath(self.srvdir, 'sshconfig'), 'r') as f:
+ with open(sshconfig_path, 'r') as f:
sshconfig.parse(f)
sshconfig = sshconfig.lookup(vagranthost)
idfile = sshconfig['identityfile']
# (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)
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'])
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'