aboutsummaryrefslogtreecommitdiffstats
path: root/roles/proxmox_hypervisor
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:23:43 -0500
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:52:13 -0500
commit0261e875679f1bf63c8d689da7fc7e014597885d (patch)
tree3f19cd74a0c1070944f75437f30b098d6ef2ffcb /roles/proxmox_hypervisor
downloadselfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.tar.gz
selfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.zip
initial commit
Diffstat (limited to 'roles/proxmox_hypervisor')
-rw-r--r--roles/proxmox_hypervisor/defaults/main.yml33
-rw-r--r--roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/20auto-upgrades3
-rw-r--r--roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/50unattended-upgrades14
l---------roles/proxmox_hypervisor/files/usr/lib/nagios/plugins1
-rw-r--r--roles/proxmox_hypervisor/handlers/main.yml24
-rw-r--r--roles/proxmox_hypervisor/tasks/chrony.yml11
-rw-r--r--roles/proxmox_hypervisor/tasks/main.yml31
-rw-r--r--roles/proxmox_hypervisor/tasks/nagios.yml68
-rw-r--r--roles/proxmox_hypervisor/tasks/postfix.yml18
-rw-r--r--roles/proxmox_hypervisor/tasks/pve.yml58
-rw-r--r--roles/proxmox_hypervisor/tasks/pve_api_user.yml21
-rw-r--r--roles/proxmox_hypervisor/tasks/pve_kvm_template.yml32
-rw-r--r--roles/proxmox_hypervisor/tasks/rsyslog.yml16
-rw-r--r--roles/proxmox_hypervisor/tasks/sudo.yml5
-rw-r--r--roles/proxmox_hypervisor/tasks/unattended_upgrades.yml11
-rw-r--r--roles/proxmox_hypervisor/tasks/zfs.yml34
-rw-r--r--roles/proxmox_hypervisor/templates/etc/chrony/chrony.conf.j210
-rw-r--r--roles/proxmox_hypervisor/templates/etc/postfix/main.cf.j219
-rw-r--r--roles/proxmox_hypervisor/templates/etc/rsyslog.d/forward.conf.j27
-rw-r--r--roles/proxmox_hypervisor/templates/etc/snmp/snmpd.conf.j210
-rw-r--r--roles/proxmox_hypervisor/templates/etc/sudoers.d/nagios.j23
-rw-r--r--roles/proxmox_hypervisor/templates/etc/sudoers.j215
-rw-r--r--roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.service.j211
-rw-r--r--roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.timer.j210
-rw-r--r--roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.service.j211
-rw-r--r--roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.timer.j210
-rw-r--r--roles/proxmox_hypervisor/templates/etc/zfs/zed.d/zed.rc.j27
-rw-r--r--roles/proxmox_hypervisor/templates/var/lib/vz/snippets/userdata.yaml.j217
-rw-r--r--roles/proxmox_hypervisor/vars/main.yml34
29 files changed, 544 insertions, 0 deletions
diff --git a/roles/proxmox_hypervisor/defaults/main.yml b/roles/proxmox_hypervisor/defaults/main.yml
new file mode 100644
index 0000000..a037eb4
--- /dev/null
+++ b/roles/proxmox_hypervisor/defaults/main.yml
@@ -0,0 +1,33 @@
+proxmox_api_user: ansible@pam
+proxmox_api_password: changeme
+
+proxmox_ntp_servers: '{{ vlan.ntp_servers }}'
+
+proxmox_mail_origin: '{{ email_domain }}'
+proxmox_relayhost: '{{ email_domain }}'
+
+proxmox_syslog_host: '{{ syslog_host_ip }}'
+proxmox_syslog_port: 514
+proxmox_syslog_proto: tcp
+
+proxmox_sudo_mailto: root
+
+proxmox_bridge: vmbr0
+proxmox_storage: local-zfs
+
+proxmox_zfs_trim_on_calendar: monthly
+proxmox_zfs_scrub_on_calendar: monthly
+
+proxmox_zed_email: root
+proxmox_zed_verbose: yes
+proxmox_zed_notify_interval_sec: 3600
+
+proxmox_nagios_ssh_pubkey: '{{ nagios_ssh_pubkey }}'
+
+proxmox_snmp_location: unknown
+proxmox_snmp_contact: '{{ organization }} Sysadmins <root@{{ email_domain }}>'
+
+snmp_v3_users:
+ - name: '{{ nagios_snmp_user }}'
+ auth_pass: '{{ nagios_snmp_auth_pass }}'
+ priv_pass: '{{ nagios_snmp_priv_pass }}'
diff --git a/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/20auto-upgrades b/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/20auto-upgrades
new file mode 100644
index 0000000..5bf85d3
--- /dev/null
+++ b/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/20auto-upgrades
@@ -0,0 +1,3 @@
+APT::Periodic::Update-Package-Lists "1";
+APT::Periodic::Unattended-Upgrade "1";
+APT::Periodic::AutocleanInterval "7";
diff --git a/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/50unattended-upgrades b/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/50unattended-upgrades
new file mode 100644
index 0000000..b2e9457
--- /dev/null
+++ b/roles/proxmox_hypervisor/files/etc/apt/apt.conf.d/50unattended-upgrades
@@ -0,0 +1,14 @@
+Unattended-Upgrade::Origins-Pattern {
+ "origin=*";
+};
+
+Unattended-Upgrade::Package-Blacklist {
+};
+
+Unattended-Upgrade::Mail "root";
+Unattended-Upgrade::MailOnlyOnError "true";
+
+Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
+Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
+Unattended-Upgrade::Remove-Unused-Dependencies "true";
+Unattended-Upgrade::Automatic-Reboot "false";
diff --git a/roles/proxmox_hypervisor/files/usr/lib/nagios/plugins b/roles/proxmox_hypervisor/files/usr/lib/nagios/plugins
new file mode 120000
index 0000000..b13c8fa
--- /dev/null
+++ b/roles/proxmox_hypervisor/files/usr/lib/nagios/plugins
@@ -0,0 +1 @@
+../../../../../nagios_client/files/usr/lib64/nagios/plugins \ No newline at end of file
diff --git a/roles/proxmox_hypervisor/handlers/main.yml b/roles/proxmox_hypervisor/handlers/main.yml
new file mode 100644
index 0000000..63fe760
--- /dev/null
+++ b/roles/proxmox_hypervisor/handlers/main.yml
@@ -0,0 +1,24 @@
+- name: restart chrony
+ systemd:
+ name: chronyd
+ state: restarted
+
+- name: restart postfix
+ systemd:
+ name: postfix
+ state: restarted
+
+- name: restart rsyslog
+ systemd:
+ name: rsyslog
+ state: restarted
+
+- name: restart zfs-zed
+ systemd:
+ name: zfs-zed
+ state: restarted
+
+- name: restart snmpd
+ systemd:
+ name: snmpd
+ state: restarted
diff --git a/roles/proxmox_hypervisor/tasks/chrony.yml b/roles/proxmox_hypervisor/tasks/chrony.yml
new file mode 100644
index 0000000..ed9b0ce
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/chrony.yml
@@ -0,0 +1,11 @@
+- name: generate chrony.conf
+ template:
+ src: etc/chrony/chrony.conf.j2
+ dest: /etc/chrony/chrony.conf
+ notify: restart chrony
+
+- name: start chrony
+ systemd:
+ name: chronyd
+ enabled: yes
+ state: started
diff --git a/roles/proxmox_hypervisor/tasks/main.yml b/roles/proxmox_hypervisor/tasks/main.yml
new file mode 100644
index 0000000..6495e74
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/main.yml
@@ -0,0 +1,31 @@
+- name: configure NTP
+ import_tasks: chrony.yml
+ tags: ntp,chrony
+
+- name: configure postfix
+ import_tasks: postfix.yml
+ tags: mail,postfix
+
+- name: configure rsyslog
+ import_tasks: rsyslog.yml
+ tags: syslog,rsyslog
+
+- name: configure sudo
+ import_tasks: sudo.yml
+ tags: sudo,sudoers
+
+- name: configure unattended upgrades
+ import_tasks: unattended_upgrades.yml
+ tags: apt,packages
+
+- name: configure ZFS
+ import_tasks: zfs.yml
+ tags: zfs
+
+- name: configure proxmox VE
+ import_tasks: pve.yml
+ tags: pve
+
+- name: configure nagios plugins
+ import_tasks: nagios.yml
+ tags: nagios
diff --git a/roles/proxmox_hypervisor/tasks/nagios.yml b/roles/proxmox_hypervisor/tasks/nagios.yml
new file mode 100644
index 0000000..b42317d
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/nagios.yml
@@ -0,0 +1,68 @@
+- name: install packages
+ apt:
+ name: '{{ proxmox_nagios_packages }}'
+ state: present
+
+- name: create nagios user
+ user:
+ name: nagios
+ comment: Nagios Pseudo-User
+ system: yes
+ shell: /bin/bash
+ home: '{{ proxmox_nagios_home }}'
+ create_home: yes
+ state: present
+
+- name: add nagios ssh key
+ authorized_key:
+ user: nagios
+ key: '{{ proxmox_nagios_ssh_pubkey }}'
+ state: present
+
+- name: copy custom nagios scripts
+ copy:
+ src: '{{ item.src }}'
+ dest: '{{ proxmox_nagios_plugin_dir }}/{{ item.path }}'
+ mode: 0555
+ loop: "{{ lookup('filetree', proxmox_nagios_plugin_dir[1:], wantlist=True) }}"
+ when: item.state == 'file'
+
+- name: generate sudo rules
+ template:
+ src: etc/sudoers.d/nagios.j2
+ dest: /etc/sudoers.d/nagios
+ mode: 0400
+
+- name: set PATH for nagios user
+ copy:
+ content: export PATH=/sbin:/bin:/usr/sbin:/usr/bin:{{ proxmox_nagios_plugin_dir }}
+ dest: '{{ proxmox_nagios_home }}/.bashrc'
+ owner: '{{ proxmox_nagios_user }}'
+ group: '{{ proxmox_nagios_user }}'
+ mode: 0644
+
+- name: stop snmpd
+ systemd:
+ name: snmpd
+ state: stopped
+
+- name: generate snmpd.conf
+ template:
+ src: etc/snmp/snmpd.conf.j2
+ dest: /etc/snmp/snmpd.conf
+ mode: 0600
+
+- name: add snmpv3 users
+ lineinfile:
+ path: /var/lib/snmp/snmpd.conf
+ line: 'createUser {{ item.name }} SHA "{{ item.auth_pass }}" AES "{{ item.priv_pass }}"'
+ insertafter: EOF
+ loop: '{{ snmp_v3_users }}'
+ loop_control:
+ label: '{{ item.name }}'
+
+- name: enable and start snmpd
+ systemd:
+ name: snmpd
+ enabled: yes
+ state: started
diff --git a/roles/proxmox_hypervisor/tasks/postfix.yml b/roles/proxmox_hypervisor/tasks/postfix.yml
new file mode 100644
index 0000000..2cb3fb2
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/postfix.yml
@@ -0,0 +1,18 @@
+- name: install postfix
+ apt:
+ name:
+ - postfix
+ - bsd-mailx
+ state: present
+
+- name: generate postifx configuration
+ template:
+ src: etc/postfix/main.cf.j2
+ dest: /etc/postfix/main.cf
+ notify: restart postfix
+
+- name: enable postfix
+ systemd:
+ name: postfix
+ enabled: yes
+ state: started
diff --git a/roles/proxmox_hypervisor/tasks/pve.yml b/roles/proxmox_hypervisor/tasks/pve.yml
new file mode 100644
index 0000000..e780bf6
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/pve.yml
@@ -0,0 +1,58 @@
+- name: disable proxmox enterprise repositiory
+ apt_repository:
+ filename: pve-enterprise
+ repo: 'deb {{ proxmox_repo_url }} {{ ansible_distribution_release }} pve-enterprise'
+ state: absent
+ update_cache: no
+
+- name: enable proxmox community repository
+ apt_repository:
+ filename: pve-no-subscription
+ repo: 'deb {{ proxmox_repo_url }} {{ ansible_distribution_release }} pve-no-subscription'
+ state: present
+ update_cache: yes
+
+- name: enable snippets on local storage
+ lineinfile:
+ path: /etc/pve/storage.cfg
+ line: ' content iso,backup,snippets,vztmpl'
+ regexp: '^\s+content\s'
+ insertafter: '^dir: local$'
+ firstmatch: yes
+
+- name: create snippets directory
+ file:
+ path: '{{ proxmox_snippets_dir }}'
+ state: directory
+
+- name: generate custom snippets
+ template:
+ src: '{{ item.src }}'
+ dest: '{{ proxmox_snippets_dir }}/{{ item.path | splitext | first }}'
+ loop: "{{ lookup('filetree', '../templates/{{ proxmox_snippets_dir[1:] }}', wantlist=True) }}"
+ when: item.state == 'file'
+
+- name: add ansible API user
+ import_tasks: pve_api_user.yml
+
+- name: create kvm image directory
+ file:
+ path: '{{ proxmox_kvm_image_dir }}'
+ state: directory
+
+- name: get current VMIDs
+ shell: qm list | awk '{print $1}'
+ register: vmids
+ changed_when: false
+
+- name: install proxmoxer
+ apt:
+ name: python3-proxmoxer
+ state: present
+
+- name: create KVM templates
+ include_tasks: pve_kvm_template.yml
+ when: (image.vmid | string) not in vmids.stdout_lines
+ loop: '{{ proxmox_kvm_images }}'
+ loop_control:
+ loop_var: image
diff --git a/roles/proxmox_hypervisor/tasks/pve_api_user.yml b/roles/proxmox_hypervisor/tasks/pve_api_user.yml
new file mode 100644
index 0000000..f620a90
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/pve_api_user.yml
@@ -0,0 +1,21 @@
+- name: create unix account
+ user:
+ name: "{{ proxmox_api_user | replace('@pam', '') }}"
+ shell: /sbin/nologin
+ password: '{{ proxmox_api_password | password_hash("sha512", proxmox_password_salt | default("")) }}'
+ state: present
+
+- name: check if user has PVE account
+ shell: pveum user list --noheader --noborder | cut -d ' ' -f1
+ changed_when: False
+ register: pve_users
+
+- name: create PVE account
+ block:
+ - name: create PVE user
+ command: pveum user add {{ proxmox_api_user }}
+
+ - name: set user ACLs
+ command: pveum acl modify / -user {{ proxmox_api_user }} -role PVEAdmin -propagate 1
+
+ when: proxmox_api_user not in pve_users.stdout_lines
diff --git a/roles/proxmox_hypervisor/tasks/pve_kvm_template.yml b/roles/proxmox_hypervisor/tasks/pve_kvm_template.yml
new file mode 100644
index 0000000..6f0dfac
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/pve_kvm_template.yml
@@ -0,0 +1,32 @@
+- name: download the disk image
+ get_url:
+ url: '{{ image.url }}'
+ checksum: 'sha256:{{ image.sha256 }}'
+ dest: '{{ proxmox_kvm_image_dir }}/{{ image.name }}.{{ image.type | default("qcow2") }}'
+
+- name: create a new VM
+ command: >
+ qm create {{ image.vmid }}
+ --name {{ image.name }}
+ --ostype {{ image.ostype | default('l26') }}
+ --scsihw virtio-scsi-pci
+ --memory 2048
+ --net0 virtio,bridge={{ proxmox_bridge }}
+ --serial0 socket
+ --vga serial0
+ --scsi1 {{ proxmox_storage }}:cloudinit
+
+- name: import the disk image
+ command: >
+ qm importdisk {{ image.vmid }}
+ {{ proxmox_kvm_image_dir }}/{{ image.name }}.{{ image.type | default("qcow2") }}
+ {{ proxmox_storage }}
+
+- name: attach disk to VM
+ command: qm set {{ image.vmid }} --scsi0 {{ proxmox_storage }}:vm-{{ image.vmid }}-disk-0
+
+- name: set boot order
+ command: qm set {{ image.vmid }} --boot order=scsi0
+
+- name: convert VM to template
+ command: qm template {{ image.vmid }}
diff --git a/roles/proxmox_hypervisor/tasks/rsyslog.yml b/roles/proxmox_hypervisor/tasks/rsyslog.yml
new file mode 100644
index 0000000..bbd981c
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/rsyslog.yml
@@ -0,0 +1,16 @@
+- name: install rsyslog
+ apt:
+ name: rsyslog
+ state: present
+
+- name: generate rsyslog configuration
+ template:
+ src: etc/rsyslog.d/forward.conf.j2
+ dest: /etc/rsyslog.d/forward.conf
+ notify: restart rsyslog
+
+- name: enable rsyslog
+ systemd:
+ name: rsyslog
+ enabled: yes
+ state: started
diff --git a/roles/proxmox_hypervisor/tasks/sudo.yml b/roles/proxmox_hypervisor/tasks/sudo.yml
new file mode 100644
index 0000000..7419bf0
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/sudo.yml
@@ -0,0 +1,5 @@
+- name: generate sudoers file
+ template:
+ src: etc/sudoers.j2
+ dest: /etc/sudoers
+ mode: 0440
diff --git a/roles/proxmox_hypervisor/tasks/unattended_upgrades.yml b/roles/proxmox_hypervisor/tasks/unattended_upgrades.yml
new file mode 100644
index 0000000..9ce7e89
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/unattended_upgrades.yml
@@ -0,0 +1,11 @@
+- name: install unattended-upgrades
+ apt:
+ name: unattended-upgrades
+
+- name: copy unattended-upgrades configuration
+ copy:
+ src: etc/apt/apt.conf.d/{{ item }}
+ dest: /etc/apt/apt.conf.d/{{ item }}
+ loop:
+ - 20auto-upgrades
+ - 50unattended-upgrades
diff --git a/roles/proxmox_hypervisor/tasks/zfs.yml b/roles/proxmox_hypervisor/tasks/zfs.yml
new file mode 100644
index 0000000..5a1587e
--- /dev/null
+++ b/roles/proxmox_hypervisor/tasks/zfs.yml
@@ -0,0 +1,34 @@
+- name: generate zed.rc
+ template:
+ src: etc/zfs/zed.d/zed.rc.j2
+ dest: /etc/zfs/zed.d/zed.rc
+ notify: restart zfs-zed
+
+- name: enable zfs event daemon
+ systemd:
+ name: zfs-zed
+ enabled: yes
+ state: started
+
+- name: create zfs systemd units
+ template:
+ src: etc/systemd/system/zfs-{{ item[0] }}@.{{ item[1] }}.j2
+ dest: /etc/systemd/system/zfs-{{ item[0] }}@.{{ item[1] }}
+ loop: "{{ ['scrub', 'trim'] | product(['service', 'timer']) }}"
+ register: zfs_units
+
+- name: reload systemd units
+ systemd:
+ daemon-reload: yes
+ when: zfs_units.changed
+
+- name: enable periodic trim and scrub for zpool
+ systemd:
+ name: zfs-{{ item }}@rpool.timer
+ state: started
+ enabled: yes
+ loop:
+ - trim
+ - scrub
+ loop_control:
+ label: zfs-{{ item }}@rpool.timer
diff --git a/roles/proxmox_hypervisor/templates/etc/chrony/chrony.conf.j2 b/roles/proxmox_hypervisor/templates/etc/chrony/chrony.conf.j2
new file mode 100644
index 0000000..e1819d7
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/chrony/chrony.conf.j2
@@ -0,0 +1,10 @@
+{% for server in proxmox_ntp_servers %}
+server {{ server }} iburst
+{% endfor %}
+
+driftfile /var/lib/chrony/chrony.drift
+makestep 1.0 3
+rtcsync
+keyfile /etc/chrony/chrony.keys
+leapsectz right/UTC
+logdir /var/log/chrony
diff --git a/roles/proxmox_hypervisor/templates/etc/postfix/main.cf.j2 b/roles/proxmox_hypervisor/templates/etc/postfix/main.cf.j2
new file mode 100644
index 0000000..76575e3
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/postfix/main.cf.j2
@@ -0,0 +1,19 @@
+compatibility_level = 2
+
+myorigin = {{ proxmox_mail_origin }}
+
+# disable local delivery
+biff = no
+mydestination =
+
+inet_interfaces = loopback-only
+inet_protocols = all
+mynetworks_style = host
+
+relayhost = {{ proxmox_relayhost }}
+
+alias_database = hash:/etc/aliases
+
+smtputf8_enable = yes
+
+smtp_tls_security_level = may
diff --git a/roles/proxmox_hypervisor/templates/etc/rsyslog.d/forward.conf.j2 b/roles/proxmox_hypervisor/templates/etc/rsyslog.d/forward.conf.j2
new file mode 100644
index 0000000..a0dd7f2
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/rsyslog.d/forward.conf.j2
@@ -0,0 +1,7 @@
+if prifilt("*.info") then {
+ action(type="omfwd"
+ target="{{ proxmox_syslog_host }}"
+ port="{{ proxmox_syslog_port }}"
+ protocol="{{ proxmox_syslog_proto }}"
+ )
+}
diff --git a/roles/proxmox_hypervisor/templates/etc/snmp/snmpd.conf.j2 b/roles/proxmox_hypervisor/templates/etc/snmp/snmpd.conf.j2
new file mode 100644
index 0000000..ad04e59
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/snmp/snmpd.conf.j2
@@ -0,0 +1,10 @@
+syslocation {{ proxmox_snmp_location }}
+syscontact {{ proxmox_snmp_contact }}
+
+sysServices 72
+
+master agentx
+
+{% for user in snmp_v3_users %}
+rouser {{ user.name }}
+{% endfor %}
diff --git a/roles/proxmox_hypervisor/templates/etc/sudoers.d/nagios.j2 b/roles/proxmox_hypervisor/templates/etc/sudoers.d/nagios.j2
new file mode 100644
index 0000000..1a1945e
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/sudoers.d/nagios.j2
@@ -0,0 +1,3 @@
+{% for command in proxmox_nagios_sudo_whitelist %}
+{{ proxmox_nagios_user }} ALL=(root) NOPASSWD: {{ command | replace(':', '\\:') }}
+{% endfor %}
diff --git a/roles/proxmox_hypervisor/templates/etc/sudoers.j2 b/roles/proxmox_hypervisor/templates/etc/sudoers.j2
new file mode 100644
index 0000000..2f14a77
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/sudoers.j2
@@ -0,0 +1,15 @@
+Defaults env_reset
+Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
+
+Defaults mailto = "{{ proxmox_sudo_mailto }}"
+Defaults mail_badpass
+Defaults mail_no_host
+Defaults mail_no_perms
+Defaults mail_no_user
+
+root ALL=(ALL:ALL) ALL
+
+# Allow members of group sudo to execute any command
+%sudo ALL=(ALL:ALL) ALL
+
+@includedir /etc/sudoers.d
diff --git a/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.service.j2 b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.service.j2
new file mode 100644
index 0000000..3dfb199
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.service.j2
@@ -0,0 +1,11 @@
+[Unit]
+Description=zpool scrub for %i
+
+[Service]
+Nice=19
+IOSchedulingClass=idle
+KillSignal=SIGINT
+ExecStart=zpool scrub %i
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.timer.j2 b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.timer.j2
new file mode 100644
index 0000000..efc33f0
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-scrub@.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=zpool scrub for %i on calendar interval
+
+[Timer]
+OnCalendar={{ proxmox_zfs_scrub_on_calendar }}
+AccuracySec=1h
+Persistent=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.service.j2 b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.service.j2
new file mode 100644
index 0000000..ef3ec43
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.service.j2
@@ -0,0 +1,11 @@
+[Unit]
+Description=zpool trim for %i
+
+[Service]
+Nice=19
+IOSchedulingClass=idle
+KillSignal=SIGINT
+ExecStart=zpool trim %i
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.timer.j2 b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.timer.j2
new file mode 100644
index 0000000..2867d0d
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/systemd/system/zfs-trim@.timer.j2
@@ -0,0 +1,10 @@
+[Unit]
+Description=Zpool trim for %i on calendar interval
+
+[Timer]
+OnCalendar={{ proxmox_zfs_trim_on_calendar }}
+AccuracySec=1h
+Persistent=true
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/proxmox_hypervisor/templates/etc/zfs/zed.d/zed.rc.j2 b/roles/proxmox_hypervisor/templates/etc/zfs/zed.d/zed.rc.j2
new file mode 100644
index 0000000..3ad418a
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/etc/zfs/zed.d/zed.rc.j2
@@ -0,0 +1,7 @@
+ZED_EMAIL_ADDR="{{ proxmox_zed_email }}"
+ZED_EMAIL_PROG="mail"
+ZED_EMAIL_OPTS="-s '@SUBJECT@' @ADDRESS@"
+ZED_NOTIFY_INTERVAL_SECS={{ proxmox_zed_notify_interval_sec }}
+ZED_NOTIFY_VERBOSE={{ proxmox_zed_verbose | bool | int }}
+ZED_USE_ENCLOSURE_LEDS=1
+ZED_SYSLOG_SUBCLASS_EXCLUDE="history_event"
diff --git a/roles/proxmox_hypervisor/templates/var/lib/vz/snippets/userdata.yaml.j2 b/roles/proxmox_hypervisor/templates/var/lib/vz/snippets/userdata.yaml.j2
new file mode 100644
index 0000000..75283cf
--- /dev/null
+++ b/roles/proxmox_hypervisor/templates/var/lib/vz/snippets/userdata.yaml.j2
@@ -0,0 +1,17 @@
+#cloud-config
+manage_etc_hosts: False
+users:
+ - name: root
+ passwd: {{ root_password | password_hash("sha512", root_password_salt | default("")) }}
+ lock_passwd: False
+ ssh_authorized_keys:
+{% for key in root_authorized_keys %}
+ - {{ key }}
+{% endfor %}
+chpasswd:
+ expire: False
+disable_root: False
+ssh_pwauth: False
+package_update: False
+package_upgrade: False
+preserve_hostname: true
diff --git a/roles/proxmox_hypervisor/vars/main.yml b/roles/proxmox_hypervisor/vars/main.yml
new file mode 100644
index 0000000..6a31caa
--- /dev/null
+++ b/roles/proxmox_hypervisor/vars/main.yml
@@ -0,0 +1,34 @@
+proxmox_repo_url: http://download.proxmox.com/debian/pve
+proxmox_snippets_dir: /var/lib/vz/snippets
+proxmox_kvm_image_dir: /usr/local/share/pve-kvm-images
+
+proxmox_kvm_images:
+ - name: rocky8.6
+ url: https://download.rockylinux.org/pub/rocky/8/images/Rocky-8-GenericCloud-8.6.20220702.0.x86_64.qcow2
+ sha256: 7b786a39eeb96e22dd85386377ff186737f6c1b9a5faa105b0a0a7a4895c29d0
+ vmid: 9002
+
+ - name: rocky8.7
+ url: https://dl.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud-Base-8.7-20221130.0.x86_64.qcow2
+ sha256: 02e5a7564c979bca08e86e4f5bfbdad9bafcf4154844f7d2a029ec3f3df0fbd9
+ vmid: 9004
+
+ - name: rocky9.0
+ url: https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-9.0-20220830.0.x86_64.qcow2
+ sha256: f02570e0ad3653df7f56baa8157739dbe92a003234acd5824dcf94d24694e20b
+ vmid: 9003
+
+ - name: rocky9.1
+ url: https://dl.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud-Base-9.1-20221130.0.x86_64.qcow2
+ sha256: 4405926b4c84edf4a25a51d5ed36bffada04e5e143045c41c974a9a9d35937f1
+ vmid: 9005
+
+proxmox_nagios_user: nagios
+proxmox_nagios_plugin_dir: /usr/lib/nagios/plugins
+proxmox_nagios_home: /var/spool/nagios
+proxmox_nagios_packages:
+ - monitoring-plugins
+ - snmpd
+
+proxmox_nagios_sudo_whitelist:
+ - /usr/bin/systemctl status -- *