Bulk update

Signed-off-by: Georg Pfuetzenreuter <georg@lysergic.dev>
This commit is contained in:
Georg Pfuetzenreuter 2022-02-13 01:37:39 +01:00
parent a2be103111
commit 642290c734
31 changed files with 404 additions and 52 deletions

11
ansible/deployment_poc/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
__pycache__/
locks/
playbooks/ghost.yml
playbooks/test.yml
shared/
templates/autoinst_*.lysergic.dev.xml.j2
templates/generated/
variables/deploy-variables.yml
*.bak
*.old
*.tgz

View File

@ -53,7 +53,7 @@
- name: Check platform
fail:
msg: The object does not contain a valid platform attribute.
when: os != 'openSUSE-Leap-x86_64'
when: os != 'openSUSE-Leap-x86_64' #support more OS's later
- name: Write tag and journal
import_tasks: "../tasks/netbox_tags_pre.yml"
@ -74,7 +74,7 @@
block:
- import_tasks: "../tasks/netbox_query_ip.yml"
- import_tasks: "../tasks/netbox_evaluate_ip.yml"
no_log: true
#no_log: true
- name: Provision virtual machine
import_tasks: "../tasks/configure_libvirt.yml"
@ -82,11 +82,30 @@
- name: Configure DHCP
import_tasks: "../tasks/init_dhcp.yml"
- name: Configure DNS
import_tasks: "../tasks/init_dns.yml"
- name: Configure Deployment Servers
import_tasks: "../tasks/init_dps.yml"
- name: Create interface object in NetBox or use existing one
block:
- import_tasks: "../tasks/netbox_init_interface.yml"
- import_tasks: "../tasks/netbox_query_interface.yml"
- import_tasks: "../tasks/netbox_evaluate_interface.yml"
#no_log: true
- name: Define IP address object in NetBox
block:
- import_tasks: "../tasks/netbox_init_ip.yml"
- import_tasks: "../tasks/netbox_primaryip.yml"
- name: Start VM and attach console
import_tasks: "../tasks/init_vm_console.yml"
# - name: Wait for guest OS installation
# import_tasks: "../tasks/wait.yml"
# - name: Prepare unattended installation (TO-DO if needed - not needed if script inside autoinst.xml fetches values itself)
# block:
# - import_tasks: "../tasks/prepare_platform_{{ os }}.yml"
always:
- name: Restore original tags
@ -100,5 +119,5 @@
- name: Debug
ansible.builtin.debug:
msg: "{{ status if status is defined}} - {{ tags if tags is defined }} - {{ host if host is defined }} - {{ host_status if host_status is defined }} - {{ os if os is defined }} - {{ vcpus if vcpus is defined }} - {{ memory if memory is defined }} - {{ disk if disk is defined }}"
msg: "{{ status if status is defined}} - {{ tags if tags is defined }} - {{ host if host is defined }} - {{ host_status if host_status is defined }} - {{ namespace if namespace is defined }} - {{ os if os is defined }} - {{ vcpus if vcpus is defined }} - {{ memory if memory is defined }} - {{ disk if disk is defined }}"

View File

@ -1,7 +1,7 @@
---
- name: Configure DHCP
block:
- name: Query DHCP server
- name: Set DHCP host OS
set_fact:
dhcp_os: "{{ hostvars[dhcp_host]['platforms'][0] }}"
@ -15,7 +15,16 @@
become: yes
become_method: doas
when: dhcp_os == 'openbsd-x86_64'
- name: Restart dhcpd
ansible.builtin.command:
argv:
- /usr/bin/doas
- rcctl
- restart
- dhcpd
when: dhcp_os == 'openbsd-x86_64'
- name: Insert DHCP static mapping
vyos.vyos.vyos_config:
backup: yes

View File

@ -0,0 +1,44 @@
---
- name: Configure DNS
block:
- name: Set FQDNs
set_fact:
dns_fqdn: "{{ lookup('community.general.dig', dns_ip + '/PTR') }}"
vm_fqdn: "{{ vm_name + '.' + namespace }}"
- name: Gather DNS hostname and zonename
set_fact:
dns_host: "{{ dns_fqdn.split('.')[0] }}"
zone: "{{ namespace.split('.')[1] + '.' + namespace.split('.')[2] }}"
- name: Set DNS host OS
set_fact:
dns_os: "{{ hostvars[dns_host]['platforms'][0] }}"
- name: Insert DNS record
ansible.builtin.blockinfile:
#backup: yes
block: "{{ lookup('template', '../templates/nsd_zone.j2') }}"
marker: "; {mark} Ansible managed block for {{ vm_name }}"
path: "/var/nsd/zones/master/{{ zone }}.zone"
when: dns_os == 'openbsd-x86_64'
delegate_to: "{{ dns_host }}"
- name: Insert DNS static host mapping
vyos.vyos.vyos_config:
backup: yes
backup_options:
dir_path: "/tmp/"
comment: "Configured as part of {{ vm_name }} deployment"
lines:
- "set system static-host-mapping host-name {{ vm_fqdn }} inet {{ ip_address }}"
- "set system static-host-mapping host-name {{ vm_fqdn }} alias {{ vm_name }}"
save: no # CHANGE BEFORE ROLLOUT
when: dns_os == 'vyos-x86_64'
delegate_to: "{{ dns_host }}"
always:
- name: Debug
ansible.builtin.debug:
msg: "{{ dns_ip if dns_ip is defined }} - {{ dns_host if dns_host is defined }} - {{ dns_fqdn if dns_fqdn is defined }} - {{ dns_os if dns_os is defined }} - {{ vm_fqdn if vm_fqdn is defined }} - {{ zone if zone is defined }}"

View File

@ -0,0 +1,54 @@
---
- name: Configure Deployment Server
block:
- name: Set DP host OS
set_fact:
dp_os: "{{ hostvars[deployment_host]['platforms'][0] }}"
- name: Prepare Grub host file
ansible.builtin.template:
src: ../templates/grub.j2
dest: "/srv/www/boot/hosts/{{ ip_address }}.cfg"
group: wheel
mode: '0444' #consider 0440 if group is changed to one shared by admins and webserver service user
when: dp_os == 'fedora-x86_64' or dp_os == 'openSUSE-Leap-x86_64'
- name: Prepare unattended installation
ansible.builtin.template:
src: "../templates/autoinst_{{ namespace }}.xml.j2"
dest: "/srv/www/autoinst_{{ vm_name }}.xml"
group: wheel
mode: '0444' #consider 0440 if group is changed to one shared by admins and webserver service user
when: dp_os == 'fedora-x86_64' or dp_os == 'openSUSE-Leap-x86_64'
- name: Prepare Grub host file for http
ansible.builtin.template:
src: ../templates/grub.j2
dest: "/var/www/htdocs/www/boot/hosts/{{ ip_address }}.cfg"
group: wheel
mode: '0444' #consider 0440 if group is changed to one shared by admins and webserver service user
when: dp_os == 'openbsd-x86_64'
- name: Prepare Grub host file for tftp
ansible.builtin.template:
src: ../templates/grub.j2
dest: "/tftpboot/boot/hosts/{{ ip_address }}.cfg"
group: wheel
mode: '0444'
when: dp_os == 'openbsd-x86_64'
- name: Generate LUKS passphrase
set_fact:
luks_passphrase: "{{ lookup('password', '/dev/null', length=15, chars=hexdigits, seed=inventory_hostname) }}"
- name: Prepare unattended installation
ansible.builtin.template:
src: "../templates/autoinst_{{ namespace }}.xml.j2"
dest: "/var/www/htdocs/www/autoinst_{{ vm_name }}.xml"
group: wheel
mode: '0444' #consider 0440 if group is changed to one shared by admins and webserver service user
when: dp_os == 'openbsd-x86_64'
delegate_to: "{{ deployment_host }}"
tags:
- init_dp

View File

@ -1,28 +1,6 @@
---
- name: Provision VM
block:
- name: Create domain template
ansible.builtin.template:
src: "../templates/libvirt-template.xml.j2"
dest: "../templates/libvirt-{{ inventory_hostname }}.xml"
group: lysergic
mode: '0660'
- name: Create storage template
ansible.builtin.template:
src: "../templates/libvirt-storage-template.xml.j2"
dest: "../templates/generated/libvirt-storage-{{ inventory_hostname }}.xml"
group: lysergic
mode: '0660'
- name: Define domain
virt:
uri: "{{ libvirt_url }}"
command: define
xml: "{{ lookup('template', '../templates/libvirt-template.xml.j2') }}"
autostart: no
# delegate_to: localhost
- name: Query volumes
ansible.builtin.command:
argv:
@ -34,6 +12,14 @@
register: volumes
no_log: true
- name: Create storage template
ansible.builtin.template:
src: "../templates/libvirt-storage-template.xml.j2"
dest: "../templates/generated/libvirt-storage-{{ inventory_hostname }}.xml"
group: lysergic
mode: '0660'
when: vm_name not in volumes.stdout
- name: Define volume
ansible.builtin.command:
argv:
@ -45,8 +31,40 @@
- "../templates/generated/libvirt-storage-{{ inventory_hostname }}.xml"
when: vm_name not in volumes.stdout
# https://gitlab.com/libvirt/libvirt/-/issues/135
- name: Fetch volume path
ansible.builtin.command:
argv:
- /usr/bin/virsh
- -c
- "{{ libvirt_url }}"
- vol-path
- --pool
- "{{ storage.name }}"
- "{{ inventory_hostname }}_root_disk.qcow2"
register: volpath
- name: Store volume path
set_fact:
volume_path: "{{ volpath.stdout }}"
- name: Create domain template
ansible.builtin.template:
src: "../templates/libvirt-template.xml.j2"
dest: "../templates/libvirt-{{ inventory_hostname }}.xml"
group: lysergic
mode: '0660'
- name: Define domain
community.libvirt.virt:
uri: "{{ libvirt_url }}"
command: define
xml: "{{ lookup('template', '../templates/libvirt-template.xml.j2') }}"
autostart: no
# delegate_to: localhost
- name: Fetch MAC address
ansible.builtin.shell: "/usr/bin/virsh -c {{ libvirt_url }} domiflist {{ vm_name }} | awk '{print $5}' | cut -d/ -f 1 | tail -n 2 | head -n1" # ewww :-(
ansible.builtin.shell: "/usr/bin/virsh -c {{ libvirt_url }} domiflist {{ vm_name }} | awk '{print $5}' | cut -d/ -f 1 | tail -n 2 | head -n 1" # ewww :-(
register: domiflist_mac
- name: Store MAC address

View File

@ -0,0 +1,7 @@
---
- name: Initialize DNS configurator
include_tasks: "../tasks/configure_dns.yml"
vars:
dns_ip: "{{ item }}"
with_items: "{{ dns_servers }}"

View File

@ -0,0 +1,9 @@
---
- name: Initialize Deployment Server configurator
include_tasks: "../tasks/configure_dps.yml"
vars:
deployment_host: "{{ item }}"
with_items: "{{ deployment_servers }}"
tags:
- init_dp

View File

@ -0,0 +1,39 @@
---
- name: Start VM and attach console inside tmux
block:
- name: Start VM
community.libvirt.virt:
uri: "{{ libvirt_url }}"
command: start
name: "{{ vm_name }}"
state: running
- name: Spawn tmux session
ansible.builtin.command:
argv:
- /usr/bin/tmux
- -S
- /tmp/ansible
- new-session
- -d
- -s
- "{{ vm_name }}"
- name: Attach console inside tmux
ansible.builtin.command:
argv:
- /usr/bin/tmux
- -S
- /tmp/ansible
- new-window
- -t
- "{{ vm_name }}"
- /usr/bin/virsh
- -c
- "{{ libvirt_url }}"
- console
- "{{ vm_name }}"
delegate_to: localhost

View File

@ -30,11 +30,16 @@
- name: Evaluate cluster host configuration
set_fact:
storage: "{{ host_choice.config_context.storage[0] }}"
#deployment_servers: "{{ host_choice.config_context.deployment_servers }}"
deployment_servers: "{{ host_choice.config_context.deployment_servers }}"
dhcp_servers: "{{ host_choice.config_context.dhcp_servers }}"
dns_servers: "{{ host_choice.config_context.dns_servers }}"
namespace: "{{ host_choice.config_context.namespace }}"
gateway: "{{ host_choice.config_context.gateway }}"
when: host_status == 'active'
tags:
- init_dp
rescue:
- name: Check retry counter
fail:

View File

@ -0,0 +1,10 @@
---
- name: Register interface ID
set_fact:
ifid: '{{ nb_interface_2.json.results[0].id }}'
when: "nb_interface_1.status|int == 400"
- name: Register interface ID
set_fact:
ifid: '{{ nb_interface_1.json.id }}'
when: "nb_interface_1.status|int == 201"

View File

@ -1,5 +1,17 @@
---
- name: Define IP address
- name: Define existing IP address
set_fact:
ip_address: "{{ nb_ip.json[0].address | ansible.netcommon.ipaddr('address') }}"
ip_address: "{{ nb_ip_1.json.results[0].address | ansible.netcommon.ipaddr('address') }}"
ip_address_cidr: "{{ nb_ip_1.json.results[0].address }}"
ip_address_type: "existing"
ipid: "{{ nb_ip_1.json.results[0].id }}"
when: "nb_ip_1.status|int == 200 and nb_ip_1.json.count|int != 0 and (nb_ip_1.json.results[0].status is defined and nb_ip_1.json.results[0].status.value == 'active')"
- name: Define new IP address
set_fact:
ip_address: "{{ nb_ip_2.json[0].address | ansible.netcommon.ipaddr('address') }}"
ip_address_cidr: "{{ nb_ip_2.json[0].address }}"
ip_address_type: "new"
when: "nb_ip_2.status is defined and nb_ip_2.status|int == 200"
tags:
- init_dp

View File

@ -3,4 +3,6 @@
set_fact:
prefix_id: "{{ nb_prefix.json.results[0].id }}"
prefix_display: "{{ nb_prefix.json.results[0].display }}"
tags:
- init_dp

View File

@ -2,4 +2,6 @@
- name: Gather site configuration
set_fact:
site_id: "{{ nb_site.json.results[0].id }}"
tags:
- init_dp

View File

@ -10,6 +10,8 @@
# set_fact:
# memory: "{{ nb_vm.json.results[0].memory }}"
# disk: "{{ nb_vm.json.results[0].disk }}"
tags:
- init_dp
- name: Pick metadata
set_fact:
@ -20,4 +22,6 @@
# # not needed, part of hostvars
# #tags: "{{ nb_vm.json.results[0].tags[0].slug }}"
# #tags: "{{ nb_vm.json.results[0].tags | sum(start=[]) | map(attribute='slug') }}"
tags:
- init_dp

View File

@ -0,0 +1,20 @@
---
- name: Create VM interface objects
ansible.builtin.uri:
url: "{{ endpoint }}/virtualization/interfaces/"
client_cert: "{{ cert }}"
client_key: "{{ key }}"
method: POST
return_content: yes
status_code:
- 201
- 400 #interface name already exists. is there an elegant way to limit 400 to this particular case? regex parsing the response text for "The fields virtual_machine, name must make a unique set." would be ugly.
headers:
Accept: application/json
Authorization: "Token {{ token }}"
body_format: json
body: ' {"virtual_machine": {{ id }}, "name": "eth0", "enabled": true, "mac_address": "{{ mac_address }}", "mode": "access"}'
register: nb_interface_1
delegate_to: localhost
#no_log: true

View File

@ -0,0 +1,20 @@
---
- name: Create IP address object
ansible.builtin.uri:
url: "{{ endpoint }}/ipam/ip-addresses/"
client_cert: "{{ cert }}"
client_key: "{{ key }}"
method: POST
return_content: yes
status_code:
- 201
- 400
headers:
Accept: application/json
Authorization: "Token {{ token }}"
body_format: json
body: ' {"address": "{{ ip_address_cidr }}", "tenant": 1, "status": "active", "assigned_object_type": "virtualization.vminterface", "assigned_object_id": {{ ifid }}, "dns_name": "{{ vm_fqdn }}"}'
register: nb_ip_3
when: "ip_address_type|string == 'new'"
delegate_to: localhost

View File

@ -0,0 +1,20 @@
---
- name: Register IP address object ID #only for new addresses, existing ones have ipid set in _evaluate_ip.yml
set_fact:
ipid: "{{ nb_ip_3.json.id }}"
when: "ip_address_type|string == 'new'"
- name: Set primary IPv4 address
ansible.builtin.uri:
url: "{{ endpoint }}/virtualization/virtual-machines/{{ id }}/"
client_cert: "{{ cert }}"
client_key: "{{ key }}"
method: PATCH
return_content: yes
headers:
Accept: application/json
Authorization: "Token {{ token }}"
body_format: json
body: ' {"primary_ip4": {{ ipid }}}'
delegate_to: localhost

View File

@ -11,4 +11,5 @@
Authorization: "Token {{ token }}"
register: nb_hosts
delegate_to: localhost
tags:
- init_dp

View File

@ -0,0 +1,15 @@
---
- name: Query existing interface
ansible.builtin.uri:
url: "{{ endpoint }}/virtualization/interfaces/?name=eth0&virtual_machine_id={{ id }}"
client_cert: "{{ cert }}"
client_key: "{{ key }}"
method: GET
return_content: yes
headers:
Accept: application/json
Authorization: "Token {{ token }}"
register: nb_interface_2
delegate_to: localhost
when: "nb_interface_1.status|int == 400"

View File

@ -1,4 +1,17 @@
---
- name: Query existing address
ansible.builtin.uri:
url: "{{ endpoint }}/ipam/ip-addresses?virtual_machine_id={{ id }}"
client_cert: "{{ cert }}"
client_key: "{{ key }}"
method: GET
return_content: yes
headers:
Accept: application/json
Authorization: "Token {{ token }}"
register: nb_ip_1
delegate_to: localhost
- name: Query available address
ansible.builtin.uri:
url: "{{ endpoint }}/ipam/prefixes/{{ prefix_id }}/available-ips/?limit=1"
@ -9,6 +22,9 @@
headers:
Accept: application/json
Authorization: "Token {{ token }}"
register: nb_ip
register: nb_ip_2
delegate_to: localhost
when: "nb_ip_1.json.count|int == 0 or (nb_ip_1.json.results[0].status is defined and nb_ip_1.json.results[0].status.value != 'active')"
tags:
- init_dp

View File

@ -11,4 +11,6 @@
Authorization: "Token {{ token }}"
register: nb_prefix
delegate_to: localhost
tags:
- init_dp

View File

@ -11,4 +11,6 @@
Authorization: "Token {{ token }}"
register: nb_site
delegate_to: localhost
tags:
- init_dp

View File

@ -12,4 +12,6 @@
Authorization: "Token {{ token }}"
register: nb_vm
delegate_to: localhost
tags:
- init_dp

View File

@ -0,0 +1,10 @@
---
- name: Wait for guest to become alive
wait_for:
delay: 240
connect_timeout: 3
sleep: 15
port: 22
host: '{{ vm_fqdn }}'
search_regex: OpenSSH
connection: local

View File

@ -1,5 +1,5 @@
host {{ vm_name }} {
hardware ethernet {{ mac_address }};
fixed-address {{ ip_address }};
filename "replace-with-bootfile";
filename "shim.efi";
}

View File

@ -0,0 +1,3 @@
default={% if os == 'openSUSE-Leap-x86_64' %}install-suse{% endif %}{% if os == 'OpenBSD-x86_64' %}install-openbsd{% endif %}
{% if os == 'openSUSE-Leap-x86_64' %}installfile=autoinst_{{ vm_name }}.xml{% endif %}

View File

@ -8,8 +8,8 @@
<format type='qcow2'/>
<permissions>
<mode>0660</mode>
<owner>107</owner>
<group>107</group>
<owner>455</owner>
<group>453</group>
</permissions>
</target>
</volume>

View File

@ -12,8 +12,11 @@
</resource>
<os>
<type arch='x86_64' machine='pc-q35-5.2'>hvm</type>
<!--loader readonly='yes' type='pflash'>/opt/firmware/OVMF_09012022_RELEASE_HTTPBOOT.fd</loader-->
<loader readonly='yes' type='pflash'>/usr/share/qemu/ovmf-x86_64-code.bin</loader>
<nvram>/var/lib/libvirt/qemu/nvram/{{ inventory_hostname }}_VARS.fd</nvram>
<boot dev='hd'/>
<boot dev='network'/>
<bootmenu enable='no'/>
</os>
<features>
@ -57,15 +60,15 @@
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<!--disk type='file' device='disk'>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/mnt/arr1-store1/vmstore1/{{ inventory_hostname }}_root_disk.qcow2' index='2'/>
<!--source pool='{{ storage.name }}' volume='{{ inventory_hostname }}_root_disk.qcow2' index='1'/-->
<source file='{{ volume_path }}'/>
<backingStore/>
<target dev='vda' bus='virtio'/>
<boot order='1'/>
<alias name='virtio-disk0'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</disk-->
</disk>
<!--disk type='file' device='cdrom'>
<driver name='qemu'/>
<source file='/mnt/iso/openSUSE-Leap-15.3-NET-x86_64.iso'/>

View File

@ -0,0 +1 @@
{{ vm_name }} IN A {{ ip_address }}

View File

@ -1,8 +0,0 @@
---
lockfile: "../locks/deploy.lock"
endpoint: ""
cert: ""
key: ""
nb_token:
libvirt_url: "qemu+tls://{{ host }}/system"
tenant: ""