File: //usr/lib/python2.7/site-packages/salt/states/lxd_profile.py
# -*- coding: utf-8 -*-
'''
Manage LXD profiles.
.. versionadded:: 2019.2.0
.. note:
- `pylxd`_ version 2 is required to let this work,
currently only available via pip.
To install on Ubuntu:
$ apt-get install libssl-dev python-pip
$ pip install -U pylxd
- you need lxd installed on the minion
for the init() and version() methods.
- for the config_get() and config_get() methods
you need to have lxd-client installed.
.. _pylxd: https://github.com/lxc/pylxd/blob/master/doc/source/installation.rst
:maintainer: René Jochum <rene@jochums.at>
:maturity: new
:depends: python-pylxd
:platform: Linux
'''
# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
# Import salt libs
from salt.exceptions import CommandExecutionError
from salt.exceptions import SaltInvocationError
import salt.ext.six as six
__docformat__ = 'restructuredtext en'
__virtualname__ = 'lxd_profile'
def __virtual__():
'''
Only load if the lxd module is available in __salt__
'''
return __virtualname__ if 'lxd.version' in __salt__ else False
def present(name, description=None, config=None, devices=None,
remote_addr=None, cert=None, key=None, verify_cert=True):
'''
Creates or updates LXD profiles
name :
The name of the profile to create/update
description :
A description string
config :
A config dict or None (None = unset).
Can also be a list:
[{'key': 'boot.autostart', 'value': 1},
{'key': 'security.privileged', 'value': '1'}]
devices :
A device dict or None (None = unset).
remote_addr :
An URL to a remote Server, you also have to give cert and key if you
provide remote_addr!
Examples:
https://myserver.lan:8443
/var/lib/mysocket.sock
cert :
PEM Formatted SSL Zertifikate.
Examples:
~/.config/lxc/client.crt
key :
PEM Formatted SSL Key.
Examples:
~/.config/lxc/client.key
verify_cert : True
Wherever to verify the cert, this is by default True
but in the most cases you want to set it off as LXD
normaly uses self-signed certificates.
See the `lxd-docs`_ for the details about the config and devices dicts.
See the `requests-docs` for the SSL stuff.
.. _lxd-docs: https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-10
.. _requests-docs: http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification # noqa
'''
ret = {
'name': name,
'description': description,
'config': config,
'devices': devices,
'remote_addr': remote_addr,
'cert': cert,
'key': key,
'verify_cert': verify_cert,
'changes': {}
}
profile = None
try:
profile = __salt__['lxd.profile_get'](
name, remote_addr, cert, key, verify_cert, _raw=True
)
except CommandExecutionError as e:
return _error(ret, six.text_type(e))
except SaltInvocationError as e:
# Profile not found
pass
if description is None:
description = six.text_type()
if profile is None:
if __opts__['test']:
# Test is on, just return that we would create the profile
msg = 'Would create the profile "{0}"'.format(name)
ret['changes'] = {'created': msg}
return _unchanged(ret, msg)
# Create the profile
try:
__salt__['lxd.profile_create'](
name,
config,
devices,
description,
remote_addr,
cert,
key,
verify_cert
)
except CommandExecutionError as e:
return _error(ret, six.text_type(e))
msg = 'Profile "{0}" has been created'.format(name)
ret['changes'] = {'created': msg}
return _success(ret, msg)
config, devices = __salt__['lxd.normalize_input_values'](
config,
devices
)
#
# Description change
#
if six.text_type(profile.description) != six.text_type(description):
ret['changes']['description'] = (
'Description changed, from "{0}" to "{1}".'
).format(profile.description, description)
profile.description = description
changes = __salt__['lxd.sync_config_devices'](
profile, config, devices, __opts__['test']
)
ret['changes'].update(changes)
if not ret['changes']:
return _success(ret, 'No changes')
if __opts__['test']:
return _unchanged(
ret,
'Profile "{0}" would get changed.'.format(name)
)
try:
__salt__['lxd.pylxd_save_object'](profile)
except CommandExecutionError as e:
return _error(ret, six.text_type(e))
return _success(ret, '{0} changes'.format(len(ret['changes'].keys())))
def absent(name, remote_addr=None, cert=None,
key=None, verify_cert=True):
'''
Ensure a LXD profile is not present, removing it if present.
name :
The name of the profile to remove.
remote_addr :
An URL to a remote Server, you also have to give cert and key if you
provide remote_addr!
Examples:
https://myserver.lan:8443
/var/lib/mysocket.sock
cert :
PEM Formatted SSL Zertifikate.
Examples:
~/.config/lxc/client.crt
key :
PEM Formatted SSL Key.
Examples:
~/.config/lxc/client.key
verify_cert : True
Wherever to verify the cert, this is by default True
but in the most cases you want to set it off as LXD
normaly uses self-signed certificates.
See the `requests-docs` for the SSL stuff.
.. _requests-docs: http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification # noqa
'''
ret = {
'name': name,
'remote_addr': remote_addr,
'cert': cert,
'key': key,
'verify_cert': verify_cert,
'changes': {}
}
if __opts__['test']:
try:
__salt__['lxd.profile_get'](
name, remote_addr, cert, key, verify_cert
)
except CommandExecutionError as e:
return _error(ret, six.text_type(e))
except SaltInvocationError as e:
# Profile not found
return _success(ret, 'Profile "{0}" not found.'.format(name))
ret['changes'] = {
'removed':
'Profile "{0}" would get deleted.'.format(name)
}
return _success(ret, ret['changes']['removed'])
try:
__salt__['lxd.profile_delete'](
name, remote_addr, cert, key, verify_cert
)
except CommandExecutionError as e:
return _error(ret, six.text_type(e))
except SaltInvocationError as e:
# Profile not found
return _success(ret, 'Profile "{0}" not found.'.format(name))
ret['changes'] = {
'removed':
'Profile "{0}" has been deleted.'.format(name)
}
return _success(ret, ret['changes']['removed'])
def _success(ret, success_msg):
ret['result'] = True
ret['comment'] = success_msg
if 'changes' not in ret:
ret['changes'] = {}
return ret
def _unchanged(ret, msg):
ret['result'] = None
ret['comment'] = msg
if 'changes' not in ret:
ret['changes'] = {}
return ret
def _error(ret, err_msg):
ret['result'] = False
ret['comment'] = err_msg
if 'changes' not in ret:
ret['changes'] = {}
return ret