mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-05-06 09:11:29 -07:00
* openstack: standardize tls params * tower: tower_verify_ssl->validate_certs * docker: use standard tls config params - cacert_path -> ca_cert - cert_path -> client_cert - key_path -> client_key - tls_verify -> validate_certs * k8s: standardize tls connection params - verify_ssl -> validate_certs - ssl_ca_cert -> ca_cert - cert_file -> client_cert - key_file -> client_key * ingate: verify_ssl -> validate_certs * manageiq: standardize tls params - verify_ssl -> validate_certs - ca_bundle_path -> ca_cert * mysql: standardize tls params - ssl_ca -> ca_cert - ssl_cert -> client_cert - ssl_key -> client_key * nios: ssl_verify -> validate_certs * postgresql: ssl_rootcert -> ca_cert * rabbitmq: standardize tls params - cacert -> ca_cert - cert -> client_cert - key -> client_key * rackspace: verify_ssl -> validate_certs * vca: verify_certs -> validate_certs * kubevirt_cdi_upload: upload_host_verify_ssl -> upload_host_validate_certs * lxd: standardize tls params - key_file -> client_key - cert_file -> client_cert * get_certificate: ca_certs -> ca_cert * get_certificate.py: clarify one or more certs in a file Co-Authored-By: jamescassell <code@james.cassell.me> * zabbix: tls_issuer -> ca_cert * bigip_device_auth_ldap: standardize tls params - ssl_check_peer -> validate_certs - ssl_client_cert -> client_cert - ssl_client_key -> client_key - ssl_ca_cert -> ca_cert * vdirect: vdirect_validate_certs -> validate_certs * mqtt: standardize tls params - ca_certs -> ca_cert - certfile -> client_cert - keyfile -> client_key * pulp_repo: standardize tls params remove `importer_ssl` prefix * rhn_register: sslcacert -> ca_cert * yum_repository: standardize tls params The fix for yum_repository is not straightforward since this module is only a thin wrapper for the underlying commands and config. In this case, we add the new values as aliases, keeping the old as primary, only due to the internal structure of the module. Aliases added: - sslcacert -> ca_cert - sslclientcert -> client_cert - sslclientkey -> client_key - sslverify -> validate_certs * gitlab_hook: enable_ssl_verification -> hook_validate_certs * Adjust arguments for docker_swarm inventory plugin. * foreman callback: standardize tls params - ssl_cert -> client_cert - ssl_key -> client_key * grafana_annotations: validate_grafana_certs -> validate_certs * nrdp callback: validate_nrdp_certs -> validate_certs * kubectl connection: standardize tls params - kubectl_cert_file -> client_cert - kubectl_key_file -> client_key - kubectl_ssl_ca_cert -> ca_cert - kubectl_verify_ssl -> validate_certs * oc connection: standardize tls params - oc_cert_file -> client_cert - oc_key_file -> client_key - oc_ssl_ca_cert -> ca_cert - oc_verify_ssl -> validate_certs * psrp connection: cert_trust_path -> ca_cert TODO: cert_validation -> validate_certs (multi-valued vs bool) * k8s inventory: standardize tls params - cert_file -> client_cert - key_file -> client_key - ca_cert -> ca_cert - verify_ssl -> validate_certs * openshift inventory: standardize tls params - cert_file -> client_cert - key_file -> client_key - ca_cert -> ca_cert - verify_ssl -> validate_certs * tower inventory: verify_ssl -> validate_certs * hashi_vault lookup: cacert -> ca_cert * k8s lookup: standardize tls params - cert_file -> client_cert - key_file -> client_key - ca_cert -> ca_cert - verify_ssl -> validate_certs * laps_passord lookup: cacert_file -> ca_cert * changelog for TLS parameter standardization
395 lines
12 KiB
Python
395 lines
12 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2016, Hiroaki Nakamura <hnakamur@gmail.com>
|
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
|
|
from __future__ import absolute_import, division, print_function
|
|
__metaclass__ = type
|
|
|
|
|
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
'status': ['preview'],
|
|
'supported_by': 'community'}
|
|
|
|
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: lxd_profile
|
|
short_description: Manage LXD profiles
|
|
version_added: "2.2"
|
|
description:
|
|
- Management of LXD profiles
|
|
author: "Hiroaki Nakamura (@hnakamur)"
|
|
options:
|
|
name:
|
|
description:
|
|
- Name of a profile.
|
|
required: true
|
|
description:
|
|
description:
|
|
- Description of the profile.
|
|
version_added: "2.5"
|
|
config:
|
|
description:
|
|
- 'The config for the container (e.g. {"limits.memory": "4GB"}).
|
|
See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#patch-3)'
|
|
- If the profile already exists and its "config" value in metadata
|
|
obtained from
|
|
GET /1.0/profiles/<name>
|
|
U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#get-19)
|
|
are different, they this module tries to apply the configurations.
|
|
- Not all config values are supported to apply the existing profile.
|
|
Maybe you need to delete and recreate a profile.
|
|
required: false
|
|
devices:
|
|
description:
|
|
- 'The devices for the profile
|
|
(e.g. {"rootfs": {"path": "/dev/kvm", "type": "unix-char"}).
|
|
See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#patch-3)'
|
|
required: false
|
|
new_name:
|
|
description:
|
|
- A new name of a profile.
|
|
- If this parameter is specified a profile will be renamed to this name.
|
|
See U(https://github.com/lxc/lxd/blob/master/doc/rest-api.md#post-11)
|
|
required: false
|
|
state:
|
|
choices:
|
|
- present
|
|
- absent
|
|
description:
|
|
- Define the state of a profile.
|
|
required: false
|
|
default: present
|
|
url:
|
|
description:
|
|
- The unix domain socket path or the https URL for the LXD server.
|
|
required: false
|
|
default: unix:/var/lib/lxd/unix.socket
|
|
snap_url:
|
|
description:
|
|
- The unix domain socket path when LXD is installed by snap package manager.
|
|
required: false
|
|
default: unix:/var/snap/lxd/common/lxd/unix.socket
|
|
version_added: '2.8'
|
|
client_key:
|
|
description:
|
|
- The client certificate key file path.
|
|
required: false
|
|
default: '"{}/.config/lxc/client.key" .format(os.environ["HOME"])'
|
|
aliases: [ key_file ]
|
|
client_cert:
|
|
description:
|
|
- The client certificate file path.
|
|
required: false
|
|
default: '"{}/.config/lxc/client.crt" .format(os.environ["HOME"])'
|
|
aliases: [ cert_file ]
|
|
trust_password:
|
|
description:
|
|
- The client trusted password.
|
|
- You need to set this password on the LXD server before
|
|
running this module using the following command.
|
|
lxc config set core.trust_password <some random password>
|
|
See U(https://www.stgraber.org/2016/04/18/lxd-api-direct-interaction/)
|
|
- If trust_password is set, this module send a request for
|
|
authentication before sending any requests.
|
|
required: false
|
|
notes:
|
|
- Profiles must have a unique name. If you attempt to create a profile
|
|
with a name that already existed in the users namespace the module will
|
|
simply return as "unchanged".
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
# An example for creating a profile
|
|
- hosts: localhost
|
|
connection: local
|
|
tasks:
|
|
- name: Create a profile
|
|
lxd_profile:
|
|
name: macvlan
|
|
state: present
|
|
config: {}
|
|
description: my macvlan profile
|
|
devices:
|
|
eth0:
|
|
nictype: macvlan
|
|
parent: br0
|
|
type: nic
|
|
|
|
# An example for creating a profile via http connection
|
|
- hosts: localhost
|
|
connection: local
|
|
tasks:
|
|
- name: create macvlan profile
|
|
lxd_profile:
|
|
url: https://127.0.0.1:8443
|
|
# These client_cert and client_key values are equal to the default values.
|
|
#client_cert: "{{ lookup('env', 'HOME') }}/.config/lxc/client.crt"
|
|
#client_key: "{{ lookup('env', 'HOME') }}/.config/lxc/client.key"
|
|
trust_password: mypassword
|
|
name: macvlan
|
|
state: present
|
|
config: {}
|
|
description: my macvlan profile
|
|
devices:
|
|
eth0:
|
|
nictype: macvlan
|
|
parent: br0
|
|
type: nic
|
|
|
|
# An example for deleting a profile
|
|
- hosts: localhost
|
|
connection: local
|
|
tasks:
|
|
- name: Delete a profile
|
|
lxd_profile:
|
|
name: macvlan
|
|
state: absent
|
|
|
|
# An example for renaming a profile
|
|
- hosts: localhost
|
|
connection: local
|
|
tasks:
|
|
- name: Rename a profile
|
|
lxd_profile:
|
|
name: macvlan
|
|
new_name: macvlan2
|
|
state: present
|
|
'''
|
|
|
|
RETURN = '''
|
|
old_state:
|
|
description: The old state of the profile
|
|
returned: success
|
|
type: str
|
|
sample: "absent"
|
|
logs:
|
|
description: The logs of requests and responses.
|
|
returned: when ansible-playbook is invoked with -vvvv.
|
|
type: list
|
|
sample: "(too long to be placed here)"
|
|
actions:
|
|
description: List of actions performed for the profile.
|
|
returned: success
|
|
type: list
|
|
sample: '["create"]'
|
|
'''
|
|
|
|
import os
|
|
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils.lxd import LXDClient, LXDClientException
|
|
|
|
|
|
# PROFILE_STATES is a list for states supported
|
|
PROFILES_STATES = [
|
|
'present', 'absent'
|
|
]
|
|
|
|
# CONFIG_PARAMS is a list of config attribute names.
|
|
CONFIG_PARAMS = [
|
|
'config', 'description', 'devices'
|
|
]
|
|
|
|
|
|
class LXDProfileManagement(object):
|
|
def __init__(self, module):
|
|
"""Management of LXC containers via Ansible.
|
|
|
|
:param module: Processed Ansible Module.
|
|
:type module: ``object``
|
|
"""
|
|
self.module = module
|
|
self.name = self.module.params['name']
|
|
self._build_config()
|
|
self.state = self.module.params['state']
|
|
self.new_name = self.module.params.get('new_name', None)
|
|
|
|
self.key_file = self.module.params.get('client_key', None)
|
|
self.cert_file = self.module.params.get('client_cert', None)
|
|
self.debug = self.module._verbosity >= 4
|
|
|
|
try:
|
|
if os.path.exists(self.module.params['snap_url'].replace('unix:', '')):
|
|
self.url = self.module.params['snap_url']
|
|
else:
|
|
self.url = self.module.params['url']
|
|
except Exception as e:
|
|
self.module.fail_json(msg=e.msg)
|
|
|
|
try:
|
|
self.client = LXDClient(
|
|
self.url, key_file=self.key_file, cert_file=self.cert_file,
|
|
debug=self.debug
|
|
)
|
|
except LXDClientException as e:
|
|
self.module.fail_json(msg=e.msg)
|
|
self.trust_password = self.module.params.get('trust_password', None)
|
|
self.actions = []
|
|
|
|
def _build_config(self):
|
|
self.config = {}
|
|
for attr in CONFIG_PARAMS:
|
|
param_val = self.module.params.get(attr, None)
|
|
if param_val is not None:
|
|
self.config[attr] = param_val
|
|
|
|
def _get_profile_json(self):
|
|
return self.client.do(
|
|
'GET', '/1.0/profiles/{0}'.format(self.name),
|
|
ok_error_codes=[404]
|
|
)
|
|
|
|
@staticmethod
|
|
def _profile_json_to_module_state(resp_json):
|
|
if resp_json['type'] == 'error':
|
|
return 'absent'
|
|
return 'present'
|
|
|
|
def _update_profile(self):
|
|
if self.state == 'present':
|
|
if self.old_state == 'absent':
|
|
if self.new_name is None:
|
|
self._create_profile()
|
|
else:
|
|
self.module.fail_json(
|
|
msg='new_name must not be set when the profile does not exist and the specified state is present',
|
|
changed=False)
|
|
else:
|
|
if self.new_name is not None and self.new_name != self.name:
|
|
self._rename_profile()
|
|
if self._needs_to_apply_profile_configs():
|
|
self._apply_profile_configs()
|
|
elif self.state == 'absent':
|
|
if self.old_state == 'present':
|
|
if self.new_name is None:
|
|
self._delete_profile()
|
|
else:
|
|
self.module.fail_json(
|
|
msg='new_name must not be set when the profile exists and the specified state is absent',
|
|
changed=False)
|
|
|
|
def _create_profile(self):
|
|
config = self.config.copy()
|
|
config['name'] = self.name
|
|
self.client.do('POST', '/1.0/profiles', config)
|
|
self.actions.append('create')
|
|
|
|
def _rename_profile(self):
|
|
config = {'name': self.new_name}
|
|
self.client.do('POST', '/1.0/profiles/{0}'.format(self.name), config)
|
|
self.actions.append('rename')
|
|
self.name = self.new_name
|
|
|
|
def _needs_to_change_profile_config(self, key):
|
|
if key not in self.config:
|
|
return False
|
|
old_configs = self.old_profile_json['metadata'].get(key, None)
|
|
return self.config[key] != old_configs
|
|
|
|
def _needs_to_apply_profile_configs(self):
|
|
return (
|
|
self._needs_to_change_profile_config('config') or
|
|
self._needs_to_change_profile_config('description') or
|
|
self._needs_to_change_profile_config('devices')
|
|
)
|
|
|
|
def _apply_profile_configs(self):
|
|
config = self.old_profile_json.copy()
|
|
for k, v in self.config.items():
|
|
config[k] = v
|
|
self.client.do('PUT', '/1.0/profiles/{0}'.format(self.name), config)
|
|
self.actions.append('apply_profile_configs')
|
|
|
|
def _delete_profile(self):
|
|
self.client.do('DELETE', '/1.0/profiles/{0}'.format(self.name))
|
|
self.actions.append('delete')
|
|
|
|
def run(self):
|
|
"""Run the main method."""
|
|
|
|
try:
|
|
if self.trust_password is not None:
|
|
self.client.authenticate(self.trust_password)
|
|
|
|
self.old_profile_json = self._get_profile_json()
|
|
self.old_state = self._profile_json_to_module_state(self.old_profile_json)
|
|
self._update_profile()
|
|
|
|
state_changed = len(self.actions) > 0
|
|
result_json = {
|
|
'changed': state_changed,
|
|
'old_state': self.old_state,
|
|
'actions': self.actions
|
|
}
|
|
if self.client.debug:
|
|
result_json['logs'] = self.client.logs
|
|
self.module.exit_json(**result_json)
|
|
except LXDClientException as e:
|
|
state_changed = len(self.actions) > 0
|
|
fail_params = {
|
|
'msg': e.msg,
|
|
'changed': state_changed,
|
|
'actions': self.actions
|
|
}
|
|
if self.client.debug:
|
|
fail_params['logs'] = e.kwargs['logs']
|
|
self.module.fail_json(**fail_params)
|
|
|
|
|
|
def main():
|
|
"""Ansible Main module."""
|
|
|
|
module = AnsibleModule(
|
|
argument_spec=dict(
|
|
name=dict(
|
|
type='str',
|
|
required=True
|
|
),
|
|
new_name=dict(
|
|
type='str',
|
|
),
|
|
config=dict(
|
|
type='dict',
|
|
),
|
|
description=dict(
|
|
type='str',
|
|
),
|
|
devices=dict(
|
|
type='dict',
|
|
),
|
|
state=dict(
|
|
choices=PROFILES_STATES,
|
|
default='present'
|
|
),
|
|
url=dict(
|
|
type='str',
|
|
default='unix:/var/lib/lxd/unix.socket'
|
|
),
|
|
snap_url=dict(
|
|
type='str',
|
|
default='unix:/var/snap/lxd/common/lxd/unix.socket'
|
|
),
|
|
client_key=dict(
|
|
type='str',
|
|
default='{0}/.config/lxc/client.key'.format(os.environ['HOME']),
|
|
aliases=['key_file']
|
|
),
|
|
client_cert=dict(
|
|
type='str',
|
|
default='{0}/.config/lxc/client.crt'.format(os.environ['HOME']),
|
|
aliases=['cert_file']
|
|
),
|
|
trust_password=dict(type='str', no_log=True)
|
|
),
|
|
supports_check_mode=False,
|
|
)
|
|
|
|
lxd_manage = LXDProfileManagement(module=module)
|
|
lxd_manage.run()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|