Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

steps:
- name: Cloning the repository repo...
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
fetch-tags: true
Expand Down
2 changes: 1 addition & 1 deletion nova/core/galaxy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace: nova
name: core
version: 6.8.18
version: 6.9.9
readme: README.md
authors:
- https://github.com/novateams
Expand Down
4 changes: 2 additions & 2 deletions nova/core/roles/accounts/tasks/unix_create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
- name: Checking if {{ vars[infra_env ~ '_template_username'] | default('') }} user exists...
ansible.builtin.stat:
path: /home/{{ vars[infra_env ~ '_template_username'] | default('') }}
register: aws_template_user
register: template_user

- name: Adding account creation source flag for {{ vars[infra_env ~ '_template_username'] | default('') }}...
ansible.builtin.lineinfile:
Expand All @@ -25,7 +25,7 @@
create: true
owner: "{{ vars[infra_env ~ '_template_username'] | default('') }}"
mode: "0600"
when: aws_template_user.stat.exists
when: template_user.stat.exists

- name: Creating accounts for...
ansible.builtin.user:
Expand Down
9 changes: 3 additions & 6 deletions nova/core/roles/cleanup/tasks/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,10 @@
executable: "/bin/{{ 'tcsh' if ansible_system | default('') == 'FreeBSD' else 'sh' if ansible_distribution | default('') == 'Alpine' else 'bash' }}"
changed_when: true

# tcsh automatically writes current history in HISTFILE
- name: Removing Linux bash history...
- name: Removing Linux shell history...
ansible.builtin.shell: |
{{ 'setenv HISTFILE "/dev/null"' if ansible_system == 'FreeBSD' else 'export HISTFILE=/dev/null' }}
rm -f /home/*/.bash_history
rm -f /root/.bash_history
history -c && {{ 'history -w && ' if ansible_system != 'FreeBSD' }}cat /dev/null > /root/.bash_history
rm -f /home/*/.*_history
rm -f /root/.*_history
args:
executable: "/bin/{{ 'tcsh' if ansible_system | default('') == 'FreeBSD' else 'sh' if ansible_distribution | default('') == 'Alpine' else 'bash' }}"
changed_when: true
Expand Down
13 changes: 13 additions & 0 deletions nova/core/roles/configure_networking/defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,16 @@ configure_networking_alpine_boot_wait_time: 60

# Time in seconds to wait for the PanOS VM to boot before sending networking configuration commands
configure_networking_panos_boot_wait_time: 60

###########
# Proxmox #
###########

# This is a list of interfaces to exclude when configuring networking on Proxmox VMs
# These are typically non-physical interfaces like loopback
configure_networking_proxmox_interfaces_to_exclude:
- lo
- lo0 # OPNsense loopback
- enc0 # OPNsense encryption
- pfsync0 # OPNsense pfsync
- pflog0 # OPNsense pflog
13 changes: 12 additions & 1 deletion nova/core/roles/configure_networking/tasks/proxmox/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,18 @@
"{{ proxmox_vm_info.proxmox_vms[0].network | map(attribute='hardware-address', default='00:00:00:00:00:00')
| reject('equalto', '00:00:00:00:00:00') | list }}"
configure_networking_hw_interfaces: "{{ proxmox_vm_info.proxmox_vms[0].network | map(attribute='name')
| reject('equalto', 'lo') | list }}"
| reject('in', configure_networking_proxmox_interfaces_to_exclude) | list }}"

- name: Checking if network customization method exists...
ansible.builtin.stat:
path: "{{ role_path }}/tasks/proxmox/{{ customization_method }}.yml"
register: customization_method_file

- name: NETWORK CUSTOMIZATION NOT IMPLEMENTED
ansible.builtin.fail:
msg: |
Network customization method {{ customization_method | upper }} is not implemented on Proxmox.
when: not customization_method_file.stat.exists

- name: Including {{ customization_method }} network configuration tasks...
ansible.builtin.include_tasks: "{{ customization_method }}.yml"
162 changes: 162 additions & 0 deletions nova/core/roles/configure_networking/tasks/proxmox/opnsense.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
---
- name: Configuring netplan on Proxmox VM...
become: false
delegate_to: localhost
block:
- name: Downloading /conf/config.xml {{ custom_vm_name | default(vm_name) }}...
ansible.builtin.uri:
url: "{{ proxmox_api_url }}/nodes/{{ proxmox_vm_info.proxmox_vms[0].node
}}/qemu/{{ proxmox_vm_info.proxmox_vms[0].vmid }}/agent/file-read?file=/conf/config.xml"
headers:
Authorization: PVEAPIToken={{ proxmox_defaults.api_user }}!{{ proxmox_defaults.api_token_id }}={{ proxmox_defaults.api_token_secret }}
method: GET
validate_certs: "{{ proxmox_validate_certs }}"
register: config_download

- name: Saving /conf/config.xml to a temporary file...
ansible.builtin.copy:
content: "{{ config_download.json.data.content }}"
dest: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
mode: "0600"

- name: Deleting existing interfaces...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/interfaces/*
state: absent

- name: Deleting existing gateways...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/OPNsense/Gateways/*
state: absent

- name: Deleting existing DNS servers...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/system/dnsserver
state: absent

- name: Templating interfaces config...
ansible.builtin.template:
src: opnsense.yml
dest: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_interfaces.yml
lstrip_blocks: true
mode: "0600"

- name: Including interfaces config...
ansible.builtin.include_vars:
file: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_interfaces.yml

- name: Configuring following opnsense interfaces for {{ inventory_hostname }}...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/interfaces
pretty_print: true
add_children: "{{ opnsense_interfaces }}"

- name: Configuring egress interface gateways for {{ inventory_hostname }}...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/OPNsense/Gateways
pretty_print: true
add_children: "{{ opnsense_gateways }}"

- name: Configuring following DNS server for {{ inventory_hostname }}...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/system
pretty_print: true
add_children:
- dnsserver: "{{ item }}"
loop: "{{ dns_server_combined }}"

- name: Enabling {{ inventory_hostname }} configured DNS servers...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/system
pretty_print: true
value: remote

- name: Adding a wan management rule for {{ inventory_hostname }}...
community.general.xml:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
xpath: /opnsense/filter
pretty_print: true
add_children:
- rule:
uuid: "{{ lookup('password', '/dev/null length=32') | ansible.builtin.to_uuid }}"
_:
- type: pass
- ipprotocol: inet46
- statetype: keep state
- direction: in
- floating: "yes"
- quick: "1"
- source:
_:
- any: "1"
- destination:
_:
- any: "1"
- descr: MGMT
when: interfaces | selectattr('egress', 'equalto', true) | first == interfaces | selectattr('connection', 'equalto', true) | first

- name: Getting network configuration file contents...
ansible.builtin.slurp:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
register: file_contents

- name: Getting the nr of config.xml chunks...
ansible.builtin.set_fact:
config_file_chunks: "{{ (file_contents.content | length + 1699) // 1700 }}"

# Writing in 1700 char chunks because otherwise the Qemu Guest Agent service fails
- name: Writing /conf/config.xml to {{ custom_vm_name | default(vm_name) }}...
ansible.builtin.uri:
url: "{{ proxmox_api_url }}/nodes/{{ proxmox_vm_info.proxmox_vms[0].node
}}/qemu/{{ proxmox_vm_info.proxmox_vms[0].vmid }}/agent/file-write"
headers:
Authorization: PVEAPIToken={{ proxmox_defaults.api_user }}!{{ proxmox_defaults.api_token_id }}={{ proxmox_defaults.api_token_secret }}
method: POST
body:
content: "{{ item | b64decode }}"
file: /tmp/config_{{ '%03d' | format(file_loop) }}.xml
body_format: json
validate_certs: "{{ proxmox_validate_certs }}"
loop: "{{ file_contents.content | regex_findall('.{1,1700}') }}"
loop_control:
index_var: file_loop
label: "{{ file_loop + 1 }}/{{ config_file_chunks }}"

- name: Removing local config.xml file...
ansible.builtin.file:
path: /tmp/{{ project_fullname | default('') }}_{{ inventory_hostname }}_opnsense_config.xml
state: absent

- name: Writing final /conf/config.xml to {{ custom_vm_name | default(vm_name) }}...
ansible.builtin.uri:
url: "{{ proxmox_api_url }}/nodes/{{ proxmox_vm_info.proxmox_vms[0].node
}}/qemu/{{ proxmox_vm_info.proxmox_vms[0].vmid }}/agent/exec"
headers:
Authorization: PVEAPIToken={{ proxmox_defaults.api_user }}!{{ proxmox_defaults.api_token_id }}={{ proxmox_defaults.api_token_secret }}
method: POST
body:
command:
- sh
- -c
- "cat /tmp/config_*.xml > /conf/config.xml && rm -f /tmp/config_*.xml"
- reboot
body_format: json
validate_certs: "{{ proxmox_validate_certs }}"
register: network_config_command

- name: Including command run check task...
ansible.builtin.include_tasks: command_run_check.yml

# This is required for network config to take effect
- name: Restarting {{ custom_vm_name | default(vm_name) }} VM...
ansible.builtin.include_role:
name: nova.core.powerstate
vars:
restart: true
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,17 @@
- ENTER

# Interfaces
# Not using | character since it gets interpreted incorrectly by the sendkey module from some keyboard layouts
- name: Sending interfaces config to {{ custom_vm_name | default(vm_name) }}...
community.vmware.vmware_guest_sendkey:
string_send: "echo {{ slurped_network_files.results[0].content }} | base64 -d > /etc/network/interfaces"
string_send:
"echo {{ slurped_network_files.results[0].content }} > /tmp/interfaces_base64 && base64
-d /tmp/interfaces_base64 > /etc/network/interfaces"
name: "{{ custom_vm_name | default(vm_name) }}"
when: slurped_network_files.results[0].content | length <= 500
when: slurped_network_files.results[0].content | length <= 1000

- name: Configuring long string interfaces file for {{ custom_vm_name | default(vm_name) }}...
when: slurped_network_files.results[0].content | length >= 500
when: slurped_network_files.results[0].content | length >= 1000
block:
- name: Sending interfaces configs to {{ custom_vm_name | default(vm_name) }}...
community.vmware.vmware_guest_sendkey:
Expand All @@ -77,7 +80,7 @@

- name: Sending base64 decode command to {{ custom_vm_name | default(vm_name) }}...
community.vmware.vmware_guest_sendkey:
string_send: "cat /tmp/interfaces_base64 | base64 -d > /etc/network/interfaces"
string_send: "base64 -d /tmp/interfaces_base64 > /etc/network/interfaces"
name: "{{ custom_vm_name | default(vm_name) }}"
keys_send:
- ENTER
Expand All @@ -91,7 +94,7 @@
# DNS
- name: Sending DNS config to {{ custom_vm_name | default(vm_name) }}...
community.vmware.vmware_guest_sendkey:
string_send: "echo {{ slurped_network_files.results[1].content }} | base64 -d > /etc/resolv.conf"
string_send: "echo {{ slurped_network_files.results[1].content }} > /tmp/resolv_conf_base64 && base64 -d /tmp/resolv_conf_base64 > /etc/resolv.conf"
name: "{{ custom_vm_name | default(vm_name) }}"

- name: Committing DNS update for {{ custom_vm_name | default(vm_name) }}...
Expand All @@ -103,7 +106,7 @@
# Network interface persistence
- name: Sending network interface persistence config to {{ custom_vm_name | default(vm_name) }}...
community.vmware.vmware_guest_sendkey:
string_send: "echo {{ slurped_network_files.results[2].content }} | base64 -d > /etc/mactab"
string_send: "echo {{ slurped_network_files.results[2].content }} > /tmp/mactab_base64 && base64 -d /tmp/mactab_base64 > /etc/mactab"
name: "{{ custom_vm_name | default(vm_name) }}"

- name: Committing network interface persistence update for {{ custom_vm_name | default(vm_name) }}...
Expand Down
5 changes: 4 additions & 1 deletion nova/core/roles/configure_networking/templates/opnsense.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
{# https://forum.netgate.com/topic/85739/change-order-of-interfaces-on-vm/13 #}
{# https://forum.netgate.com/topic/159909/adding-an-interface-to-a-pfsense-esx-vm-causes-them-to-be-re-ordered-on-reboot #}

{% if infra_env == "vsphere" %}
{% if interfaces | length == 1 %}
{% set nic_map = ["vmx0"] %}
{% elif interfaces | length == 2 %}
Expand All @@ -23,6 +23,9 @@
{% elif interfaces | length == 10 %}
{% set nic_map = ["vmx2","vmx5","vmx8","vmx0","vmx3","vmx6","vmx9","vmx1","vmx4","vmx7"] %}
{% endif %}
{% else %}
{% set nic_map = configure_networking_hw_interfaces %}
{% endif %}

opnsense_interfaces:
{% for interface in interfaces %}
Expand Down
4 changes: 4 additions & 0 deletions nova/core/roles/connection/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
ansible.builtin.include_tasks: proxmox.yml
when: infra_env == 'proxmox'

- name: Configuring connection in OpenStack environment...
ansible.builtin.include_tasks: openstack.yml
when: infra_env == 'openstack'

- name: Configuring connection for external or pre-existing machine...
ansible.builtin.include_tasks: external.yml
when: infra_env == 'external'
Expand Down
16 changes: 16 additions & 0 deletions nova/core/roles/connection/tasks/openstack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
- name:
Connecting as {{ openstack_template_username | default(template_username) if fresh_deploy else ansible_deployer_username
}} to {{ inventory_hostname }} using {{ default_connection_plugin | upper
}} over {{ connection_address_custom | default(connection_address) }}... # noqa: name[template]
ansible.builtin.set_fact:
ansible_host: "{{ connection_address_custom | default(connection_address) }}"
ansible_connection: "{{ default_connection_plugin }}"
ansible_user: "{{ openstack_template_username | default(template_username) if fresh_deploy else ansible_deployer_username }}"
ansible_password: "{{ openstack_template_password | default(template_password) if fresh_deploy else ansible_deployer_password }}"

# Initial connection will be done with temporary SSH key
ansible_private_key_file: "{{ machine_operations_openstack_temp_ssh_key_path if fresh_deploy else omit }}"
# To avoid SSH MaxAuthTries limit
ansible_ssh_extra_args: "{{ connection_custom_ansible_ssh_extra_args
| default('-o IdentitiesOnly=yes' if fresh_deploy else omit) }}"
Loading