mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 17:33:54 +00:00
350 lines
11 KiB
Python
350 lines
11 KiB
Python
# -*- 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 []
|