mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
Add support for connecting via https with a client certificate
This commit is contained in:
parent
684291d461
commit
bb69e7030c
1 changed files with 90 additions and 6 deletions
|
@ -128,6 +128,34 @@ options:
|
||||||
- The unix domain socket path for the LXD server.
|
- The unix domain socket path for the LXD server.
|
||||||
required: false
|
required: false
|
||||||
default: /var/lib/lxd/unix.socket
|
default: /var/lib/lxd/unix.socket
|
||||||
|
url:
|
||||||
|
description:
|
||||||
|
- The https URL for the LXD server.
|
||||||
|
- If url is set, this module connects to the LXD server via https.
|
||||||
|
If url it not set, this module connects to the LXD server via
|
||||||
|
unix domain socket specified with unix_socket_path.
|
||||||
|
key_file:
|
||||||
|
description:
|
||||||
|
- The client certificate key file path.
|
||||||
|
required: false
|
||||||
|
default: >
|
||||||
|
'{}/.config/lxc/client.key'.format(os.environ['HOME'])
|
||||||
|
cert_file:
|
||||||
|
description:
|
||||||
|
- The client certificate file path.
|
||||||
|
required: false
|
||||||
|
default: >
|
||||||
|
'{}/.config/lxc/client.crt'.format(os.environ['HOME'])
|
||||||
|
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 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:
|
notes:
|
||||||
- Containers must have a unique name. If you attempt to create a container
|
- Containers must have a unique name. If you attempt to create a container
|
||||||
with a name that already existed in the users namespace the module will
|
with a name that already existed in the users namespace the module will
|
||||||
|
@ -205,11 +233,17 @@ EXAMPLES = """
|
||||||
alias: "ubuntu/xenial/amd64"
|
alias: "ubuntu/xenial/amd64"
|
||||||
profiles: ["default"]
|
profiles: ["default"]
|
||||||
|
|
||||||
|
# An example for connecting to the LXD server using https
|
||||||
- hosts: localhost
|
- hosts: localhost
|
||||||
connection: local
|
connection: local
|
||||||
tasks:
|
tasks:
|
||||||
- name: create macvlan profile
|
- name: create macvlan profile
|
||||||
lxd_container:
|
lxd_container:
|
||||||
|
url: https://127.0.0.1:8443
|
||||||
|
# These cert_file and key_file values are equal to the default values.
|
||||||
|
#cert_file: "{{ lookup('env', 'HOME') }}/.config/lxc/client.crt"
|
||||||
|
#key_file: "{{ lookup('env', 'HOME') }}/.config/lxc/client.key"
|
||||||
|
trust_password: mypassword
|
||||||
type: profile
|
type: profile
|
||||||
name: macvlan
|
name: macvlan
|
||||||
state: present
|
state: present
|
||||||
|
@ -247,6 +281,8 @@ lxd_container:
|
||||||
sample: ["create", "start"]
|
sample: ["create", "start"]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -254,11 +290,12 @@ except ImportError:
|
||||||
|
|
||||||
# httplib/http.client connection using unix domain socket
|
# httplib/http.client connection using unix domain socket
|
||||||
import socket
|
import socket
|
||||||
|
import ssl
|
||||||
try:
|
try:
|
||||||
from httplib import HTTPConnection
|
from httplib import HTTPConnection, HTTPSConnection
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# Python 3
|
# Python 3
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection, HTTPSConnection
|
||||||
|
|
||||||
class UnixHTTPConnection(HTTPConnection):
|
class UnixHTTPConnection(HTTPConnection):
|
||||||
def __init__(self, path, timeout=None):
|
def __init__(self, path, timeout=None):
|
||||||
|
@ -270,6 +307,12 @@ class UnixHTTPConnection(HTTPConnection):
|
||||||
sock.connect(self.path)
|
sock.connect(self.path)
|
||||||
self.sock = sock
|
self.sock = sock
|
||||||
|
|
||||||
|
from ansible.module_utils.urls import generic_urlparse
|
||||||
|
try:
|
||||||
|
from urlparse import urlparse
|
||||||
|
except ImportError:
|
||||||
|
# Python 3
|
||||||
|
from url.parse import urlparse
|
||||||
|
|
||||||
# LXD_ANSIBLE_STATES is a map of states that contain values of methods used
|
# LXD_ANSIBLE_STATES is a map of states that contain values of methods used
|
||||||
# when a particular state is evoked.
|
# when a particular state is evoked.
|
||||||
|
@ -326,7 +369,17 @@ class LxdContainerManagement(object):
|
||||||
self.force_stop = self.module.params['force_stop']
|
self.force_stop = self.module.params['force_stop']
|
||||||
self.addresses = None
|
self.addresses = None
|
||||||
self.unix_socket_path = self.module.params['unix_socket_path']
|
self.unix_socket_path = self.module.params['unix_socket_path']
|
||||||
self.connection = UnixHTTPConnection(self.unix_socket_path, timeout=self.timeout)
|
self.url = self.module.params.get('url', None)
|
||||||
|
self.key_file = self.module.params.get('key_file', None)
|
||||||
|
self.cert_file = self.module.params.get('cert_file', None)
|
||||||
|
self.trust_password = self.module.params.get('trust_password', None)
|
||||||
|
if self.url is None:
|
||||||
|
self.connection = UnixHTTPConnection(self.unix_socket_path, timeout=self.timeout)
|
||||||
|
else:
|
||||||
|
parts = generic_urlparse(urlparse(self.url))
|
||||||
|
ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||||
|
ctx.load_cert_chain(self.cert_file, keyfile=self.key_file)
|
||||||
|
self.connection = HTTPSConnection(parts.get('netloc'), context=ctx, timeout=self.timeout)
|
||||||
self.logs = []
|
self.logs = []
|
||||||
self.actions = []
|
self.actions = []
|
||||||
|
|
||||||
|
@ -337,6 +390,10 @@ class LxdContainerManagement(object):
|
||||||
if param_val is not None:
|
if param_val is not None:
|
||||||
self.config[attr] = param_val
|
self.config[attr] = param_val
|
||||||
|
|
||||||
|
def _authenticate(self):
|
||||||
|
body_json = {'type': 'client', 'password': self.trust_password}
|
||||||
|
self._send_request('POST', '/1.0/certificates', body_json=body_json)
|
||||||
|
|
||||||
def _send_request(self, method, url, body_json=None, ok_error_codes=None):
|
def _send_request(self, method, url, body_json=None, ok_error_codes=None):
|
||||||
try:
|
try:
|
||||||
body = json.dumps(body_json)
|
body = json.dumps(body_json)
|
||||||
|
@ -359,8 +416,18 @@ class LxdContainerManagement(object):
|
||||||
logs=self.logs
|
logs=self.logs
|
||||||
)
|
)
|
||||||
return resp_json
|
return resp_json
|
||||||
except socket.error:
|
except socket.error as e:
|
||||||
self.module.fail_json(msg='cannot connect to the LXD server', unix_socket_path=self.unix_socket_path)
|
if self.url is None:
|
||||||
|
self.module.fail_json(
|
||||||
|
msg='cannot connect to the LXD server',
|
||||||
|
unix_socket_path=self.unix_socket_path, error=e
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.module.fail_json(
|
||||||
|
msg='cannot connect to the LXD server',
|
||||||
|
url=self.url, key_file=self.key_file, cert_file=self.cert_file,
|
||||||
|
error=e
|
||||||
|
)
|
||||||
|
|
||||||
def _operate_and_wait(self, method, path, body_json=None):
|
def _operate_and_wait(self, method, path, body_json=None):
|
||||||
resp_json = self._send_request(method, path, body_json=body_json)
|
resp_json = self._send_request(method, path, body_json=body_json)
|
||||||
|
@ -604,7 +671,7 @@ class LxdContainerManagement(object):
|
||||||
self.actions.append('create')
|
self.actions.append('create')
|
||||||
|
|
||||||
def _rename_profile(self):
|
def _rename_profile(self):
|
||||||
config = { 'name': self.new_name }
|
config = {'name': self.new_name}
|
||||||
self._send_request('POST', '/1.0/profiles/{}'.format(self.name), config)
|
self._send_request('POST', '/1.0/profiles/{}'.format(self.name), config)
|
||||||
self.actions.append('rename')
|
self.actions.append('rename')
|
||||||
self.name = self.new_name
|
self.name = self.new_name
|
||||||
|
@ -636,6 +703,9 @@ class LxdContainerManagement(object):
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Run the main method."""
|
"""Run the main method."""
|
||||||
|
|
||||||
|
if self.trust_password is not None:
|
||||||
|
self._authenticate()
|
||||||
|
|
||||||
if self.type == 'container':
|
if self.type == 'container':
|
||||||
self.old_container_json = self._get_container_json()
|
self.old_container_json = self._get_container_json()
|
||||||
self.old_state = self._container_json_to_module_state(self.old_container_json)
|
self.old_state = self._container_json_to_module_state(self.old_container_json)
|
||||||
|
@ -715,6 +785,20 @@ def main():
|
||||||
unix_socket_path=dict(
|
unix_socket_path=dict(
|
||||||
type='str',
|
type='str',
|
||||||
default='/var/lib/lxd/unix.socket'
|
default='/var/lib/lxd/unix.socket'
|
||||||
|
),
|
||||||
|
url=dict(
|
||||||
|
type='str',
|
||||||
|
),
|
||||||
|
key_file=dict(
|
||||||
|
type='str',
|
||||||
|
default='{}/.config/lxc/client.key'.format(os.environ['HOME'])
|
||||||
|
),
|
||||||
|
cert_file=dict(
|
||||||
|
type='str',
|
||||||
|
default='{}/.config/lxc/client.crt'.format(os.environ['HOME'])
|
||||||
|
),
|
||||||
|
trust_password=dict(
|
||||||
|
type='str',
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
supports_check_mode=False,
|
supports_check_mode=False,
|
||||||
|
|
Loading…
Reference in a new issue