File: //usr/lib/python2.7/site-packages/salt/modules/vbox_guest.py
# -*- coding: utf-8 -*-
'''
VirtualBox Guest Additions installer
'''
from __future__ import absolute_import, print_function, unicode_literals
# Import python libs
import contextlib
import functools
import glob
import logging
import os
import re
import tempfile
# Import Salt libs
from salt.ext import six
log = logging.getLogger(__name__)
__virtualname__ = 'vbox_guest'
_additions_dir_prefix = 'VBoxGuestAdditions'
_shared_folders_group = 'vboxsf'
def __virtual__():
'''
Set the vbox_guest module if the OS Linux
'''
if __grains__.get('kernel', '') not in ('Linux', ):
return (False, 'The vbox_guest execution module failed to load: only available on Linux systems.')
return __virtualname__
def additions_mount():
'''
Mount VirtualBox Guest Additions CD to the temp directory.
To connect VirtualBox Guest Additions via VirtualBox graphical interface
press 'Host+D' ('Host' is usually 'Right Ctrl').
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.additions_mount
:return: True or OSError exception
'''
mount_point = tempfile.mkdtemp()
ret = __salt__['mount.mount'](mount_point, '/dev/cdrom')
if ret is True:
return mount_point
else:
raise OSError(ret)
def additions_umount(mount_point):
'''
Unmount VirtualBox Guest Additions CD from the temp directory.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.additions_umount
:param mount_point: directory VirtualBox Guest Additions is mounted to
:return: True or an string with error
'''
ret = __salt__['mount.umount'](mount_point)
if ret:
os.rmdir(mount_point)
return ret
@contextlib.contextmanager
def _additions_mounted():
mount_point = additions_mount()
yield mount_point
additions_umount(mount_point)
def _return_mount_error(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except OSError as e:
return six.text_type(e)
return wrapper
def _additions_install_program_path(mount_point):
return os.path.join(mount_point, {
'Linux': 'VBoxLinuxAdditions.run',
'Solaris': 'VBoxSolarisAdditions.pkg',
'Windows': 'VBoxWindowsAdditions.exe'
}[__grains__.get('kernel', '')])
def _additions_install_opensuse(**kwargs):
kernel_type = re.sub(
r'^(\d|\.|-)*', '', __grains__.get('kernelrelease', ''))
kernel_devel = 'kernel-{0}-devel'.format(kernel_type)
return __states__['pkg.installed'](None, pkgs=['make', 'gcc', kernel_devel])
def _additions_install_ubuntu(**kwargs):
return __states__['pkg.installed'](None, pkgs=['dkms', ])
def _additions_install_fedora(**kwargs):
return __states__['pkg.installed'](None, pkgs=['dkms', 'gcc'])
def _additions_install_linux(mount_point, **kwargs):
reboot = kwargs.pop('reboot', False)
restart_x11 = kwargs.pop('restart_x11', False)
upgrade_os = kwargs.pop('upgrade_os', False)
if upgrade_os:
__salt__['pkg.upgrade']()
# dangerous: do not call variable `os` as it will hide os module
guest_os = __grains__.get('os', '')
if guest_os == 'openSUSE':
_additions_install_opensuse(**kwargs)
elif guest_os == 'ubuntu':
_additions_install_ubuntu(**kwargs)
elif guest_os == 'fedora':
_additions_install_fedora(**kwargs)
else:
log.warning("%s is not fully supported yet.", guest_os)
installer_path = _additions_install_program_path(mount_point)
installer_ret = __salt__['cmd.run_all'](installer_path)
if installer_ret['retcode'] in (0, 1):
if reboot:
__salt__['system.reboot']()
elif restart_x11:
raise NotImplementedError("Restarting x11 is not supported yet.")
else:
# VirtualBox script enables module itself, need to restart OS
# anyway, probably don't need that.
# for service in ('vboxadd', 'vboxadd-service', 'vboxadd-x11'):
# __salt__['service.start'](service)
pass
return additions_version()
elif installer_ret['retcode'] in (127, '127'):
return ("'{0}' not found on CD. Make sure that VirtualBox Guest "
"Additions CD is attached to the CD IDE Controller.".format(
os.path.basename(installer_path)))
else:
return installer_ret['stderr']
@_return_mount_error
def additions_install(**kwargs):
'''
Install VirtualBox Guest Additions. Uses the CD, connected by VirtualBox.
To connect VirtualBox Guest Additions via VirtualBox graphical interface
press 'Host+D' ('Host' is usually 'Right Ctrl').
See https://www.virtualbox.org/manual/ch04.html#idp52733088 for more details.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.additions_install
salt '*' vbox_guest.additions_install reboot=True
salt '*' vbox_guest.additions_install upgrade_os=True
:param reboot: reboot computer to complete installation
:type reboot: bool
:param upgrade_os: upgrade OS (to ensure the latests version of kernel and developer tools are installed)
:type upgrade_os: bool
:return: version of VirtualBox Guest Additions or string with error
'''
with _additions_mounted() as mount_point:
kernel = __grains__.get('kernel', '')
if kernel == 'Linux':
return _additions_install_linux(mount_point, **kwargs)
def _additions_dir():
root = '/opt'
dirs = glob.glob(os.path.join(root, _additions_dir_prefix) + '*')
if dirs:
return dirs[0]
else:
raise EnvironmentError('No VirtualBox Guest Additions dirs found!')
def _additions_remove_linux_run(cmd):
uninstaller_ret = __salt__['cmd.run_all'](cmd)
return uninstaller_ret['retcode'] in (0, )
def _additions_remove_linux(**kwargs):
try:
return _additions_remove_linux_run(
os.path.join(_additions_dir(), 'uninstall.sh'))
except EnvironmentError:
return False
def _additions_remove_linux_use_cd(mount_point, **kwargs):
force = kwargs.pop('force', False)
args = ''
if force:
args += '--force'
return _additions_remove_linux_run('{program} uninstall {args}'.format(
program=_additions_install_program_path(mount_point), args=args))
@_return_mount_error
def _additions_remove_use_cd(**kwargs):
'''
Remove VirtualBox Guest Additions.
It uses the CD, connected by VirtualBox.
'''
with _additions_mounted() as mount_point:
kernel = __grains__.get('kernel', '')
if kernel == 'Linux':
return _additions_remove_linux_use_cd(mount_point, **kwargs)
def additions_remove(**kwargs):
'''
Remove VirtualBox Guest Additions.
Firstly it tries to uninstall itself by executing
'/opt/VBoxGuestAdditions-VERSION/uninstall.run uninstall'.
It uses the CD, connected by VirtualBox if it failes.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.additions_remove
salt '*' vbox_guest.additions_remove force=True
:param force: force VirtualBox Guest Additions removing
:type force: bool
:return: True if VirtualBox Guest Additions were removed successfully else False
'''
kernel = __grains__.get('kernel', '')
if kernel == 'Linux':
ret = _additions_remove_linux()
if not ret:
ret = _additions_remove_use_cd(**kwargs)
return ret
def additions_version():
'''
Check VirtualBox Guest Additions version.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.additions_version
:return: version of VirtualBox Guest Additions or False if they are not installed
'''
try:
d = _additions_dir()
except EnvironmentError:
return False
if d and len(os.listdir(d)) > 0:
return re.sub(r'^{0}-'.format(_additions_dir_prefix), '',
os.path.basename(d))
return False
def grant_access_to_shared_folders_to(name, users=None):
'''
Grant access to auto-mounted shared folders to the users.
User is specified by it's name. To grant access for several users use argument `users`.
Access will be denied to the users not listed in `users` argument.
See https://www.virtualbox.org/manual/ch04.html#sf_mount_auto for more details.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.grant_access_to_shared_folders_to fred
salt '*' vbox_guest.grant_access_to_shared_folders_to users ['fred', 'roman']
:param name: name of the user to grant access to auto-mounted shared folders to
:type name: str
:param users: list of names of users to grant access to auto-mounted shared folders to (if specified, `name` will not be taken into account)
:type users: list of str
:return: list of users who have access to auto-mounted shared folders
'''
if users is None:
users = [name]
if __salt__['group.members'](_shared_folders_group, ','.join(users)):
return users
else:
if not __salt__['group.info'](_shared_folders_group):
if not additions_version:
return ("VirtualBox Guest Additions are not installed. Ιnstall "
"them firstly. You can do it with the help of command "
"vbox_guest.additions_install.")
else:
return (
"VirtualBox Guest Additions seems to be installed, but "
"group '{0}' not found. Check your installation and fix "
"it. You can uninstall VirtualBox Guest Additions with "
"the help of command :py:func:`vbox_guest.additions_remove "
"<salt.modules.vbox_guest.additions_remove> (it has "
"`force` argument to fix complex situations; use "
"it with care) and then install it again. You can do "
"it with the help of :py:func:`vbox_guest.additions_install "
"<salt.modules.vbox_guest.additions_install>`."
"".format(_shared_folders_group))
else:
return ("Cannot replace members of the '{0}' group."
"".format(_shared_folders_group))
def list_shared_folders_users():
'''
List users who have access to auto-mounted shared folders.
See https://www.virtualbox.org/manual/ch04.html#sf_mount_auto for more details.
CLI Example:
.. code-block:: bash
salt '*' vbox_guest.list_shared_folders_users
:return: list of users who have access to auto-mounted shared folders
'''
try:
return __salt__['group.info'](_shared_folders_group)['members']
except KeyError:
return []