salt/salt/modules/vbox_guest.py

350 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
'''
VirtualBox Guest Additions installer
'''
from __future__ import absolute_import
# Import python libs
import contextlib
import functools
import glob
import logging
import os
import re
import tempfile
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
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 str(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)
ret = __salt__['state.single']('pkg.installed', 'devel packages',
pkgs=['make', 'gcc', kernel_devel])
return ret
def _additions_install_ubuntu(**kwargs):
ret = __salt__['state.single']('pkg.installed', 'devel packages',
pkgs=['dkms', ])
return ret
def _additions_install_fedora(**kwargs):
ret = __salt__['state.single']('pkg.installed', 'devel packages',
pkgs=['dkms', 'gcc'])
return ret
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("{0} is not fully supported yet.".format(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 []