Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions playbooks/site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@
tags: [prometheus]
when: *prometheus

- role: helper/vmdns
tags: [vmdns]

- hosts: "{{ node_group | d('node') }}"
tags: [node, stage2]
collections:
Expand Down
43 changes: 43 additions & 0 deletions roles/helper/vmdns/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Role: opennebula.deploy.helper.vmdns
====================================

A role that automatically updates /etc/hosts on the RAFT leader.

Requirements
------------

N/A

Role Variables
--------------

| Name | Type | Default | Description |
|----------------|-------|---------|--------------------------------------------------------------------|
| `vmdns_server` | `str` | `null` | DNS service to configure (currently only `resolved` is supported). |

Dependencies
------------

- ansible.posix

Example Playbook
----------------

- hosts: frontend
vars:
leader_hook: raft/failover.sh
follower_hook: raft/failover.sh
vmdns_server: resolved
roles:
- role: opennebula.deploy.helper.facts
- role: opennebula.deploy.helper.vmdns

License
-------

Apache-2.0

Author Information
------------------

[OpenNebula Systems](https://opennebula.io/)
2 changes: 2 additions & 0 deletions roles/helper/vmdns/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
vmdns_server: null # [null, 'resolved']
67 changes: 67 additions & 0 deletions roles/helper/vmdns/files/refresh.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/usr/bin/env ruby
# managed by one-deploy

def run(cmd)
o = `#{cmd}`
s = $?
raise unless s.success?
o
end

def debounce(lock_file = '/var/tmp/vmdns.lock')
File.open(lock_file, File::CREAT | File::RDWR, 0o0644) do |lf|
next unless lf.flock(File::LOCK_EX | File::LOCK_NB)
begin
# NOTE: This is not completely precise, but should be good enough
# for a simple reduction.
sleep(1)
yield
ensure
lf.flock(File::LOCK_UN)
end
end
end

def refresh(hosts_file = '/etc/hosts')
File.open(hosts_file, File::RDONLY) do |hf|
hf.each_line(chomp: true).each_with_object({block: false, lines: []}) do |line, acc|
case line
when '# BEGIN VMDNS (one-deploy)'
acc[:block] = true
when '# END VMDNS (one-deploy)'
acc[:block] = false
else
acc[:lines] << line unless acc[:block]
end
end[:lines]
end.then do |unmanaged|
require 'json'

document = JSON.parse run('onevm list --json')

File.open(hosts_file, File::CREAT | File::TRUNC | File::WRONLY, 0o0644) do |hf|
unmanaged.each do |line|
hf.puts(line)
end

hf.puts('# BEGIN VMDNS (one-deploy)')

document.dig('VM_POOL', 'VM')&.each do |vm|
ip = [vm.dig('TEMPLATE', 'NIC')].flatten.dig(0, 'IP')
next unless ip

name = vm['NAME']
next unless name

id = vm['ID']
next unless id

hf.puts("#{ip} #{name} one-#{id}")
end

hf.puts('# END VMDNS (one-deploy)')
end
end
end

debounce { refresh }
7 changes: 7 additions & 0 deletions roles/helper/vmdns/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
collections:
- opennebula.deploy
- ansible.posix

dependencies:
- role: opennebula.deploy.common
147 changes: 147 additions & 0 deletions roles/helper/vmdns/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
---
- when: vmdns_server in ['resolved']
vars:
_use_ha: >-
{{ use_ha | d((force_ha | bool is true) or (federation.groups.frontend | count > 1)) }}
_files:
- dest: /var/lib/one/remotes/hooks/vmdns/
state: directory
mode: u=rwx,g=rx,o=

- when: "{{ _use_ha }}"
dest: /var/lib/one/remotes/hooks/raft/failover.d/01-vmdns.rb
src: /var/lib/one/remotes/hooks/vmdns/refresh.rb
state: link
force: true

- when: "{{ vmdns_server == 'resolved' }}"
dest: /etc/systemd/resolved.conf.d/
state: directory
owner: 0
group: 0
mode: u=rwx,go=rx

_configs:
- dest: /etc/systemd/resolved.conf.d/99-vmdns.conf
mode: u=rw,go=r
content: |
# managed by one-deploy
[Resolve]
DNSStubListenerExtra=0.0.0.0
_scripts:
- dest: /var/lib/one/remotes/hooks/vmdns/refresh.rb
src: "{{ role_path }}/files/refresh.rb"
mode: u=rwx,g=rx,o=

_templates:
- TEMPLATE:
NAME: vmdns_insert
TYPE: api
CALL: one.template.instantiate
RESOURCE: VM
REMOTE: 'NO'
TIMEOUT: 60
COMMAND: /var/lib/one/remotes/hooks/vmdns/refresh.rb

- TEMPLATE:
NAME: vmdns_remove
TYPE: state
RESOURCE: VM
REMOTE: 'NO'
'ON': DONE # Ansible converts ON to True otherwise..
TIMEOUT: 60
COMMAND: /var/lib/one/remotes/hooks/vmdns/refresh.rb
block:
- name: Assert that it is possible to install working RAFT hook
ansible.builtin.assert:
that: (_use_ha is false)
or
(leader_hook == 'raft/failover.sh' and follower_hook == 'raft/failover.sh')
fail_msg: Please switch to raft/failover.sh for VIP management first.

- ansible.builtin.include_role:
name: opennebula/leader
when: leader is undefined

- name: Install required OS packages
ansible.builtin.package:
name: "{{ _common + _specific[ansible_os_family] }}"
vars:
_common: [acl]
_specific:
Debian: []
RedHat: []
Suse: []
register: package
until: package is success
retries: 12
delay: 5

- name: Grant oneadmin access to /etc/hosts
ansible.posix.acl:
path: /etc/hosts
entity: 9869
etype: user
permissions: rw
state: present

- name: Touch files and directories
ansible.builtin.file:
dest: "{{ item.dest }}"
src: "{{ item.src | d(omit) }}"
state: "{{ item.state }}"
force: "{{ item.force | d(false) }}"
owner: "{{ item.owner | d(9869) }}"
group: "{{ item.group | d(9869) }}"
mode: "{{ item.mode | d(omit) }}"
when: item.when | d(true)
loop: "{{ _files }}"

- name: Create configs and scripts
ansible.builtin.copy:
dest: "{{ item.dest }}"
src: "{{ item.src | d(omit) }}"
content: "{{ item.content | d(omit) }}"
owner: "{{ item.owner | d(9869) }}"
group: "{{ item.group | d(9869) }}"
mode: "{{ item.mode }}"
when: item.when | d(true)
loop: "{{ _configs + _scripts }}"
register: copy_configs_and_scripts

- name: Restart systemd-resolved
ansible.builtin.systemd_service:
name: systemd-resolved.service
state: restarted
when:
- vmdns_server == 'resolved'
- copy_configs_and_scripts is changed

- when: inventory_hostname == leader
block:
- name: Create hooks
ansible.builtin.shell:
cmd: |
set -o errexit
TEMPLATE="$(mktemp)" && trap "rm -rf $TEMPLATE" EXIT ERR
tee "$TEMPLATE"
if onehook show '{{ item.TEMPLATE.NAME }}'; then
exit 0
fi
onehook create "$TEMPLATE"
exit 78 # EREMCHG
stdin: >-
{{ item.TEMPLATE | opennebula.deploy.to_one }}
executable: /bin/bash
register: shell
changed_when:
- shell.rc in [78]
failed_when:
- shell.rc not in [0, 78]
loop: "{{ _templates }}"
2 changes: 2 additions & 0 deletions roles/opennebula/common/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ keep_empty_bridge: true
admin_pubkey: "{{ _admin_pubkey_loaded }}"
zone_name: "{{ ('OpenNebula' if (federation.role != 'SLAVE') else undef()) | mandatory('The zone_name var must be provided.') }}"
auth: { default: null }
leader_hook: raft/vip.sh
follower_hook: raft/vip.sh
42 changes: 22 additions & 20 deletions roles/opennebula/server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,28 @@ N/A
Role Variables
--------------

| Name | Type | Default | Example | Description |
|---------------------|--------|--------------|---------------|-----------------------------------------------------------------------------------------------------------------|
| `one_pass` | `str` | `null` | `asd123` | Use specific password for the `oneadmin` user. |
| `force_ha` | `bool` | `false` | | Deploy OpenNebula in HA mode even with a single Frontend. |
| `unsafe_migrations` | `bool` | `true` | | Disable LibVirt's NFS/mountpoint checks. |
| `keep_empty_bridge` | `bool` | `true` | | Make sure empty network bridges are never removed (from Nodes). |
| `one_vip` | `str` | undefined | `10.11.12.13` | When OpenNebula is in HA mode it points to the Leader. |
| `one_vip_if` | `str` | undefined | `eth0` | NIC device to assign the `one_vip` address to (on Frontends). |
| `one_vip_cidr` | `int` | undefined | `24` | CIDR prefix of the subnet `one_vip` is allocated in. |
| `db_backend` | `str` | `MariaDB` | |`MariaDB` or `SQLite`. |
| `db_name` | `str` | `opennebula` | | Name of the database/schema used by OpenNebula. |
| `db_owner` | `str` | `oneadmin` | | User used by OpenNebula to access the database. |
| `db_password` | `str` | `opennebula` | | Password used by OpenNebula to authenticate the user. |
| `gate_endpoint` | `str` | conditional | (check below) | An URL used to reach the OneGate endpoint (HTTP). |
| `admin_pubkey` | `str` | loaded | (check below) | SSH pubkey loaded from `/var/lib/one/.ssh/id_rsa.pub`, provided by the user (as string) or ignored when `null`. |
| `sched_rank` | `dict` | undefined | (check below) | Rank scheduler configuration. |
| `sched_drs` | `dict` | undefined | (check below) | OpenNebula Distributed Resource Scheduler configuration. |
| `auth.default` | `str` | `null` | | Pick default auth mechanism (currently only `ldap` is supported in one-deploy). |
| `auth.ldap.config` | `dict` | `{}` | (check below) | LDAP authentication config (/etc/one/auth/ldap_auth.conf). |
| `auth.ldap.mapping` | `dict` | `{}` | (check below) | LDAP authentication group mapping (manually defined). |
| Name | Type | Default | Example | Description |
|---------------------|--------|---------------|---------------|-----------------------------------------------------------------------------------------------------------------|
| `one_pass` | `str` | `null` | `asd123` | Use specific password for the `oneadmin` user. |
| `force_ha` | `bool` | `false` | | Deploy OpenNebula in HA mode even with a single Frontend. |
| `unsafe_migrations` | `bool` | `true` | | Disable LibVirt's NFS/mountpoint checks. |
| `keep_empty_bridge` | `bool` | `true` | | Make sure empty network bridges are never removed (from Nodes). |
| `one_vip` | `str` | undefined | `10.11.12.13` | When OpenNebula is in HA mode it points to the Leader. |
| `one_vip_if` | `str` | undefined | `eth0` | NIC device to assign the `one_vip` address to (on Frontends). |
| `one_vip_cidr` | `int` | undefined | `24` | CIDR prefix of the subnet `one_vip` is allocated in. |
| `leader_hook` | `str` | `raft/vip.sh` | | Define RAFT leader VIP handler. |
| `follower_hook` | `str` | `raft/vip.sh` | | Define RAFT follower VIP handler. |
| `db_backend` | `str` | `MariaDB` | |`MariaDB` or `SQLite`. |
| `db_name` | `str` | `opennebula` | | Name of the database/schema used by OpenNebula. |
| `db_owner` | `str` | `oneadmin` | | User used by OpenNebula to access the database. |
| `db_password` | `str` | `opennebula` | | Password used by OpenNebula to authenticate the user. |
| `gate_endpoint` | `str` | conditional | (check below) | An URL used to reach the OneGate endpoint (HTTP). |
| `admin_pubkey` | `str` | loaded | (check below) | SSH pubkey loaded from `/var/lib/one/.ssh/id_rsa.pub`, provided by the user (as string) or ignored when `null`. |
| `sched_rank` | `dict` | undefined | (check below) | Rank scheduler configuration. |
| `sched_drs` | `dict` | undefined | (check below) | OpenNebula Distributed Resource Scheduler configuration. |
| `auth.default` | `str` | `null` | | Pick default auth mechanism (currently only `ldap` is supported in one-deploy). |
| `auth.ldap.config` | `dict` | `{}` | (check below) | LDAP authentication config (/etc/one/auth/ldap_auth.conf). |
| `auth.ldap.mapping` | `dict` | `{}` | (check below) | LDAP authentication group mapping (manually defined). |

Dependencies
------------
Expand Down
11 changes: 11 additions & 0 deletions roles/opennebula/server/files/failover.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
# managed by one-deploy

set -o errexit; shopt -s nullglob

/var/lib/one/remotes/hooks/raft/vip.sh "$@"

for SCRIPT in /var/lib/one/remotes/hooks/raft/failover.d/[0-9][0-9]-*; do
if ! [[ -x "$SCRIPT" ]]; then continue; fi
$SCRIPT "$@"
done
26 changes: 24 additions & 2 deletions roles/opennebula/server/tasks/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -209,20 +209,42 @@

- when: use_ha is true
block:
- when: _hooks is contains('raft/failover.sh')
vars:
_hooks:
- "{{ leader_hook }}"
- "{{ follower_hook }}"
block:
- name: Create raft/failover.d
ansible.builtin.file:
path: /var/lib/one/remotes/hooks/raft/failover.d
state: directory
owner: 9869
group: 9869
mode: u=rwx,g=rx,o=

- name: Create raft/failover.sh
ansible.builtin.copy:
dest: /var/lib/one/remotes/hooks/raft/failover.sh
src: "{{ role_path }}/files/failover.sh"
owner: 9869
group: 9869
mode: u=rwx,g=rx,o=

- name: Configure oned (RAFT)
opennebula.deploy.cfgtool:
dest: /etc/one/oned.conf
parser: One
actions:
- put:
path: [RAFT_LEADER_HOOK, COMMAND]
value: '"raft/vip.sh"'
value: '"{{ leader_hook }}"'
- put:
path: [RAFT_LEADER_HOOK, ARGUMENTS]
value: '"leader {{ one_vip_if }} {{ one_vip }}/{{ one_vip_cidr }}"'
- put:
path: [RAFT_FOLLOWER_HOOK, COMMAND]
value: '"raft/vip.sh"'
value: '"{{ follower_hook }}"'
- put:
path: [RAFT_FOLLOWER_HOOK, ARGUMENTS]
value: '"follower {{ one_vip_if }} {{ one_vip }}/{{ one_vip_cidr }}"'
Expand Down