Browse Source

Merge branch 'wip-libvirt' into 'master'

libvirt: configure the hypervisor with docker and VPN

See merge request main/infrastructure!463
keep-around/141c32a47adcad608753260c73db05e159850641
Loïc Dachary 1 month ago
parent
commit
141c32a47a
  1. 5
      docs/release-notes.rst
  2. 57
      docs/user-guide.rst
  3. 1
      enough/cli/libvirt.py
  4. 3
      enough/common/__init__.py
  5. 5
      enough/common/libvirt.py
  6. 6
      inventory/group_vars/all/openvpn.yml
  7. 68
      libvirt-hypervisor-playbook.yml
  8. 3
      playbooks/openvpn/roles/openvpn/defaults/main.yml
  9. 9
      playbooks/openvpn/roles/openvpn/tasks/openvpn.yml
  10. 1
      playbooks/openvpn/roles/openvpn/templates/ccd/lan.j2
  11. 29
      tests/enough/common/test_libvirt.py
  12. 2
      tests/enough/test_cmd.py

5
docs/release-notes.rst

@ -1,6 +1,11 @@
Release Notes
=============
2.1.27
------
* Add `enough libvirt install --vpn` to connect the libvirt hypervisor to a VPN.
2.1.26
------

57
docs/user-guide.rst

@ -167,6 +167,13 @@ The libvirt daemon and tools must be installed as follows:
enough --domain lan.example.com libvirt install 192.168.1.19
.. note::
If a docker was installed on the hypervisor, the daemon must be
restarted with `systemctl restart docker` so that it re-installs
its iptables rules because the installation of the libvirt daemon
discards them.
Create the DNS name server
~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -176,6 +183,56 @@ Create the DNS name server
enough --domain lan.example.com service create bind --driver libvirt
Connecting libvirt and OpenStack Enough instances
-------------------------------------------------
The `OpenStack` Enough instance runs a VPN server to which a host of
the `libvirt` Enough instance connects as a client. Routes are setup
so that all hosts in both the `OpenStack` and `libvirt` Enough
instances can communicate.
The `libvirt` hypervisor is also a client of the VPN so that system
administration can be done remotely.
Assuming the `libvirt` hypervisor client is defined in
`~/.enough/example.com/inventory/group_vars/all/openvpn.yml` as follows:
.. code::
---
#
#############################################
#
# List of active openvpn clients
#
openvpn_active_clients:
- hypervisor
After running the VPN service as follows:
.. code::
$ enough --domain example.com service create --host bind-host openvpn
The file `~/.enough/example.com/openvpn/hypervisor.tar.gz` is created
and must be manually copied from `example.com` to `lan.example.com` in
the file `~/.enough/lan.example.com/hypervisor.tar.gz`.
It can then be used to configure the `lan.example.com` hypervisor as a
VPN client of `example.com` as follows:
.. code::
$ enough --domain lan.example.com libvirt install \
--vpn hypervisor.tar.gz 192.168.1.19
Finally it must be started as follows:
.. code::
$ systemctl start openvpn-client@hypervisor
Create or update a service
--------------------------

1
enough/cli/libvirt.py

@ -9,6 +9,7 @@ class Install(Command):
def get_parser(self, prog_name):
parser = super().get_parser(prog_name)
parser.add_argument('--vpn', help='relative path to VPN credentials')
parser.add_argument('host')
return parser

3
enough/common/__init__.py

@ -316,5 +316,4 @@ class Enough(object):
self.libvirt.backup_prune(OpenStack(self.config_dir, **self.args))
def libvirt_install(self):
return libvirt_install(self.config_dir, self.share_dir,
self.args['domain'], self.args['host'])
return libvirt_install(self.config_dir, self.share_dir, **self.args)

5
enough/common/libvirt.py

@ -12,11 +12,12 @@ from enough.common import retry
log = logging.getLogger(__name__)
def libvirt_install(config_dir, share_dir, domain, ip):
Hosts(config_dir).create_or_update('libvirt-hypervisor', ip, '22')
def libvirt_install(config_dir, share_dir, **kwargs):
Hosts(config_dir).create_or_update('libvirt-hypervisor', kwargs['host'], '22')
playbook = ansible_utils.Playbook(config_dir, share_dir)
playbook.run('--private-key', f'{config_dir}/infrastructure_key',
'--limit', 'libvirt-hypervisor,localhost',
'--extra-vars', f'vpn={kwargs.get("vpn","NOOP")}',
f'{share_dir}/libvirt-hypervisor-playbook.yml')
return True

6
inventory/group_vars/all/openvpn.yml

@ -19,3 +19,9 @@ openvpn_active_clients: []
# openvpn_active_clients
#
openvpn_retired_clients: []
#
######################################################
#
# DO NOT MODIFY VARIABLES BELOW THIS LINE
#
openvpn_easy_rsa_root: /etc

68
libvirt-hypervisor-playbook.yml

@ -1,33 +1,81 @@
---
- import_playbook: "{{ '$SHARE_DIR/playbooks/misc/sexy-debian-playbook.yml' | expandvars }}"
- name: install libvirt
- name: install libvirt hypervisor
hosts: libvirt-hypervisor
become: true
pre_tasks:
- name: apt-get install libvirt
- name: apt-get install libvirt common
apt:
name:
- libvirt-clients
- libguestfs-tools
- virtinst
- python3-libvirt
- python3-lxml
- libvirt-dev
- pkg-config
- libvirt-daemon-system
- name: apt-get install libvirt python bullseye
apt:
name:
- python3-libvirt
- python3-lxml
when: ansible_distribution_release == 'bullseye'
- name: apt-get install libvirt
- name: apt-get install libvirt python buster
apt:
name:
- libvirt-clients
- libguestfs-tools
- virtinst
- python-libvirt
- python-lxml
- libvirt-dev
- pkg-config
when: ansible_distribution_release == 'buster'
- name: load enough in .bashrc
blockinfile:
path: /home/{{ ansible_user }}/.bashrc
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
block: |
eval "$(docker run --rm enoughcommunity/enough:latest install)"
- when: ansible_distribution_release == 'buster'
block:
- import_role:
name: ansible-role-docker
- import_role:
name: docker
- name: connect libvirt hypervisor to VPN
hosts: libvirt-hypervisor
become: true
pre_tasks:
- when: vpn != "NOOP"
block:
- name: apt-get install openvpn
apt:
name:
- openvpn
- name: copy VPN credentials
copy:
src: "{{ enough_domain_config_directory }}/{{ vpn }}"
dest: "/etc/openvpn/client/hypervisor.tar.gz"
- name: expand credentials
shell: |
tar zxvf hypervisor.tar.gz
args:
chdir: "/etc/openvpn/client"
- name: systemctl enable openvpn-client@hypervisor
service:
name: openvpn-client@hypervisor
enabled: yes
state: stopped

3
playbooks/openvpn/roles/openvpn/defaults/main.yml

@ -21,6 +21,8 @@ openvpn_ou: Enough Community
#
openvpn_server_conf: |
push "route {{ openstack_internal_network_prefix }}.0 255.255.255.0"
route {{ libvirt_network_external_prefix }}.0 255.255.255.0
push "route {{ libvirt_network_external_prefix }}.0 255.255.255.0"
#
######################################################
#
@ -42,4 +44,3 @@ openvpn_public_ip: "{{ ansible_host }}"
#
openvpn_local_directory: /tmp/enough-openvpn
openvpn_overwrite_nftables_conf: yes
openvpn_easy_rsa_root: /etc

9
playbooks/openvpn/roles/openvpn/tasks/openvpn.yml

@ -19,9 +19,9 @@
ifup {{ network_secondary_interface }}:1
when: interface is changed
- name: apt-get install openvpn nftables
- name: apt-get install openvpn easy-rsa nftables
apt:
name: [openvpn, nftables]
name: [openvpn, easy-rsa, nftables]
state: present
- name: net.ipv4.ip_forward=1
@ -91,6 +91,11 @@
path: /etc/openvpn/ccd
mode: 0755
- name: /etc/openvpn/ccd/lan
template:
src: ccd/lan.j2
dest: /etc/openvpn/ccd/lan
- name: /etc/openvpn/server.conf
template:
src: server.conf.j2

1
playbooks/openvpn/roles/openvpn/templates/ccd/lan.j2

@ -0,0 +1 @@
iroute {{ openstack_internal_network_prefix }}.0 255.255.255.0

29
tests/enough/common/test_libvirt.py

@ -9,22 +9,39 @@ from enough.common.dotenough import Hosts, DotEnoughLibvirt
@pytest.mark.libvirt_integration
def test_libvirt_install(dotenough_libvirt_fixture):
lv = libvirt.Libvirt(dotenough_libvirt_fixture.config_dir, '.',
config_dir = dotenough_libvirt_fixture.config_dir
open(f'{config_dir}/hypervisor.conf', 'w').write('SOME')
sh.tar('zcvf', 'hypervisor.tar.gz', 'hypervisor.conf', _cwd=config_dir)
lv = libvirt.Libvirt(config_dir, '.',
domain=dotenough_libvirt_fixture.domain)
info = lv.create_or_update([dotenough_libvirt_fixture.prefix])
assert info[dotenough_libvirt_fixture.prefix]['port'] == '22'
hypervisor_ip = info[dotenough_libvirt_fixture.prefix]['ipv4']
assert libvirt.libvirt_install(dotenough_libvirt_fixture.config_dir, '.',
dotenough_libvirt_fixture.domain,
hypervisor_ip) is True
hosts = Hosts(dotenough_libvirt_fixture.config_dir)
dotenough = DotEnoughLibvirt(dotenough_libvirt_fixture.config_dir,
assert libvirt.libvirt_install(config_dir, '.',
host=hypervisor_ip,
vpn="hypervisor.tar.gz") is True
hosts = Hosts(config_dir)
dotenough = DotEnoughLibvirt(config_dir,
dotenough_libvirt_fixture.domain)
assert hosts.get_ip('libvirt-hypervisor') == hypervisor_ip
assert sh.ssh('-oStrictHostKeyChecking=no',
'-i', dotenough.private_key(), f'debian@{hypervisor_ip}',
'which', 'virsh').exit_code == 0
r = sh.ssh('-oStrictHostKeyChecking=no',
'-i', dotenough.private_key(), f'debian@{hypervisor_ip}',
'docker', 'version')
assert 'Docker Engine' in r.stdout.decode('utf-8')
r = sh.ssh('-oStrictHostKeyChecking=no',
'-i', dotenough.private_key(), f'debian@{hypervisor_ip}',
'systemctl', 'list-units', '--all', 'openvpn*')
# print('====================================')
# print(r.stdout.decode('utf-8'))
assert 'openvpn-client@hypervisor' in r.stdout.decode('utf-8')
@pytest.mark.libvirt_integration
def test_libvirt_network_all(dotenough_libvirt_fixture):

2
tests/enough/test_cmd.py

@ -54,7 +54,7 @@ def test_libvirt_command(capsys, mocker):
mocker.patch('enough.common.Enough.set_args', set_args)
mocker.patch('enough.common.libvirt_install',
side_effect=lambda *args: print('LIBVIRT'))
side_effect=lambda *args, **kwargs: print('LIBVIRT'))
assert cmd.main(['libvirt', 'install', '1.2.3.4']) == 0
out, err = capsys.readouterr()
assert 'LIBVIRT' in out

Loading…
Cancel
Save