WIP
This commit is contained in:
37
.ansible-lint
Normal file
37
.ansible-lint
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
profile: basic
|
||||||
|
|
||||||
|
# Paths to exclude from linting
|
||||||
|
exclude_paths:
|
||||||
|
- .ansible/
|
||||||
|
- collections/ansible_collections/
|
||||||
|
- roles/geerlingguy.java/
|
||||||
|
- roles/oatakan.rhel_ovirt_template/
|
||||||
|
- roles/oatakan.rhel_template_build/
|
||||||
|
- roles/oatakan.windows_template_build/
|
||||||
|
- roles/oatakan.windows_update/
|
||||||
|
- roles/oatakan.windows_virtio/
|
||||||
|
- roles/ikke_t.container_image_cleanup/
|
||||||
|
- roles/ikke_t.podman_container_systemd/
|
||||||
|
- roles/sage905.mineos/
|
||||||
|
- roles/sage905.waterfall/
|
||||||
|
|
||||||
|
# Warn rather than fail on these during initial adoption
|
||||||
|
warn_list:
|
||||||
|
- yaml[line-length]
|
||||||
|
- name[casing]
|
||||||
|
- fqcn[action-core]
|
||||||
|
- no-changed-when
|
||||||
|
|
||||||
|
# Rules to skip entirely during initial adoption
|
||||||
|
skip_list:
|
||||||
|
- role-name # toal-common doesn't follow FQCN yet
|
||||||
|
|
||||||
|
# Use progressive mode: only flag new violations on changed files
|
||||||
|
# (useful for gradual adoption in existing projects)
|
||||||
|
# progressive: true
|
||||||
|
|
||||||
|
mock_modules:
|
||||||
|
- community.general.proxmox_kvm
|
||||||
|
|
||||||
|
mock_roles: []
|
||||||
7
.claude/settings.json
Normal file
7
.claude/settings.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(du:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,5 +33,6 @@
|
|||||||
"mounts": [
|
"mounts": [
|
||||||
"source=${localEnv:XDG_RUNTIME_DIR}/containers/auth.json,target=/container-auth.json,type=bind,consistency=cached",
|
"source=${localEnv:XDG_RUNTIME_DIR}/containers/auth.json,target=/container-auth.json,type=bind,consistency=cached",
|
||||||
"source=${localEnv:HOME}/Dev/inventories/toallab-inventory,target=/workspaces/inventory,type=bind,consistency=cached",
|
"source=${localEnv:HOME}/Dev/inventories/toallab-inventory,target=/workspaces/inventory,type=bind,consistency=cached",
|
||||||
|
"source=${localEnv:HOME}/Dev/ansible_collections/,target=/workspaces/collections/,type=bind,consistency=cached",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -107,7 +107,14 @@ venv.bak/
|
|||||||
|
|
||||||
# Ansible
|
# Ansible
|
||||||
*.retry
|
*.retry
|
||||||
|
ansible-navigator.log
|
||||||
|
.ansible/
|
||||||
|
|
||||||
|
# Vendor roles (install via roles/requirements.yml)
|
||||||
|
roles/geerlingguy.*
|
||||||
|
roles/oatakan.*
|
||||||
|
roles/ikke_t.*
|
||||||
|
roles/sage905.*
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
keys/
|
keys/
|
||||||
|
|||||||
@@ -3,3 +3,26 @@ repos:
|
|||||||
rev: v8.18.2
|
rev: v8.18.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: gitleaks
|
- id: gitleaks
|
||||||
|
|
||||||
|
- repo: https://github.com/adrienverge/yamllint
|
||||||
|
rev: v1.35.1
|
||||||
|
hooks:
|
||||||
|
- id: yamllint
|
||||||
|
args: [--config-file, .yamllint]
|
||||||
|
exclude: |
|
||||||
|
(?x)^(
|
||||||
|
roles/geerlingguy\..*/|
|
||||||
|
roles/oatakan\..*/|
|
||||||
|
roles/ikke_t\..*/|
|
||||||
|
roles/sage905\..*/|
|
||||||
|
\.ansible/|
|
||||||
|
collections/ansible_collections/
|
||||||
|
)
|
||||||
|
|
||||||
|
- repo: https://github.com/ansible/ansible-lint
|
||||||
|
rev: v25.1.3
|
||||||
|
hooks:
|
||||||
|
- id: ansible-lint
|
||||||
|
# ansible-lint reads .ansible-lint for configuration
|
||||||
|
additional_dependencies:
|
||||||
|
- ansible-core>=2.15
|
||||||
|
|||||||
39
.yamllint
Normal file
39
.yamllint
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
extends: default
|
||||||
|
|
||||||
|
rules:
|
||||||
|
# Allow longer lines for readability in tasks
|
||||||
|
line-length:
|
||||||
|
max: 160
|
||||||
|
level: warning
|
||||||
|
|
||||||
|
# Allow both true/false and yes/no boolean styles
|
||||||
|
truthy:
|
||||||
|
allowed-values: ['true', 'false', 'yes', 'no']
|
||||||
|
check-keys: false
|
||||||
|
|
||||||
|
# Ansible uses double-bracket Jinja2 - allow in strings
|
||||||
|
braces:
|
||||||
|
min-spaces-inside: 0
|
||||||
|
max-spaces-inside: 1
|
||||||
|
|
||||||
|
# Allow some indentation flexibility for Ansible block style
|
||||||
|
indentation:
|
||||||
|
spaces: 2
|
||||||
|
indent-sequences: true
|
||||||
|
check-multi-line-strings: false
|
||||||
|
|
||||||
|
# Comments should have a space after #
|
||||||
|
comments:
|
||||||
|
min-spaces-from-content: 1
|
||||||
|
|
||||||
|
# Don't require document-start marker on every file
|
||||||
|
document-start: disable
|
||||||
|
|
||||||
|
ignore: |
|
||||||
|
roles/geerlingguy.*
|
||||||
|
roles/oatakan.*
|
||||||
|
roles/ikke_t.*
|
||||||
|
roles/sage905.*
|
||||||
|
.ansible/
|
||||||
|
collections/ansible_collections/
|
||||||
44
ansible.cfg
Normal file
44
ansible.cfg
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[defaults]
|
||||||
|
# Inventory - override with -i or ANSIBLE_INVENTORY env var
|
||||||
|
inventory = /workspaces/inventory
|
||||||
|
|
||||||
|
# Role and collection paths
|
||||||
|
roles_path = roles
|
||||||
|
collections_path = /workspaces/collections:~/.ansible/collections
|
||||||
|
|
||||||
|
# Interpreter discovery
|
||||||
|
interpreter_python = auto_silent
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
gathering = smart
|
||||||
|
fact_caching = jsonfile
|
||||||
|
fact_caching_connection = /tmp/ansible_fact_cache
|
||||||
|
fact_caching_timeout = 3600
|
||||||
|
|
||||||
|
# Output
|
||||||
|
stdout_callback = yaml
|
||||||
|
bin_ansible_callbacks = True
|
||||||
|
callbacks_enabled = profile_tasks
|
||||||
|
|
||||||
|
# SSH settings
|
||||||
|
host_key_checking = False
|
||||||
|
timeout = 30
|
||||||
|
|
||||||
|
# Vault
|
||||||
|
vault_password_file = vault-id-from-op-client.sh
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
retry_files_enabled = False
|
||||||
|
nocows = True
|
||||||
|
|
||||||
|
[inventory]
|
||||||
|
# Enable inventory plugins
|
||||||
|
enable_plugins = host_list, yaml, ini, auto, toml
|
||||||
|
|
||||||
|
[privilege_escalation]
|
||||||
|
become = False
|
||||||
|
become_method = sudo
|
||||||
|
|
||||||
|
[ssh_connection]
|
||||||
|
pipelining = True
|
||||||
|
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
import ipaddress
|
|
||||||
import yaml
|
|
||||||
import os
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
def load_yaml_input(file_path):
|
|
||||||
with open(file_path, "r") as f:
|
|
||||||
return yaml.safe_load(f)
|
|
||||||
|
|
||||||
def group_by_subnet(data, mask=24):
|
|
||||||
grouped = defaultdict(list)
|
|
||||||
|
|
||||||
for record in data:
|
|
||||||
ip_str = record.get("address")
|
|
||||||
if not ip_str:
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
ip = ipaddress.ip_address(ip_str)
|
|
||||||
network = ipaddress.ip_network(f"{ip}/{mask}", strict=False)
|
|
||||||
grouped[str(network)].append(record)
|
|
||||||
except ValueError:
|
|
||||||
print(f"Skipping invalid IP: {ip_str}")
|
|
||||||
|
|
||||||
return grouped
|
|
||||||
|
|
||||||
def save_groups_to_yaml(grouped, output_dir="."):
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
|
|
||||||
for subnet, entries in grouped.items():
|
|
||||||
safe_subnet = subnet.replace("/", "_")
|
|
||||||
filename = os.path.join(output_dir, f"subnet_{safe_subnet}.yaml")
|
|
||||||
with open(filename, "w") as f:
|
|
||||||
yaml.dump(entries, f, default_flow_style=False)
|
|
||||||
print(f"Saved {len(entries)} entries to {filename}")
|
|
||||||
|
|
||||||
def main():
|
|
||||||
input_file = "input.yaml" # change as needed
|
|
||||||
output_dir = "output_subnets"
|
|
||||||
cidr_mask = 24 # change to desired subnet size
|
|
||||||
|
|
||||||
records = load_yaml_input(input_file)
|
|
||||||
grouped = group_by_subnet(records, cidr_mask)
|
|
||||||
save_groups_to_yaml(grouped, output_dir)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
---
|
|
||||||
- name: VM Provisioning
|
|
||||||
hosts: tag_ansible:&tag_tower
|
|
||||||
connection: local
|
|
||||||
collections:
|
|
||||||
- redhat.rhv
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- block:
|
|
||||||
- name: Obtain SSO token from username / password credentials
|
|
||||||
ovirt_auth:
|
|
||||||
url: "{{ ovirt_url }}"
|
|
||||||
username: "{{ ovirt_username }}"
|
|
||||||
password: "{{ ovirt_password }}"
|
|
||||||
|
|
||||||
- name: Disks Created
|
|
||||||
ovirt_disk:
|
|
||||||
auth: "{{ ovirt_auth }}"
|
|
||||||
description: "Boot Disk for {{ inventory_hostname }}"
|
|
||||||
interface: virtio
|
|
||||||
size: 120GiB
|
|
||||||
storage_domain: nas_iscsi
|
|
||||||
bootable: True
|
|
||||||
wait: true
|
|
||||||
name: "{{ inventory_hostname }}_disk0"
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: VM Created
|
|
||||||
ovirt_vm:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- name: Add NIC to VM
|
|
||||||
ovirt_nic:
|
|
||||||
state: present
|
|
||||||
vm:
|
|
||||||
name: mynic
|
|
||||||
interface: e1000
|
|
||||||
mac_address: 00:1a:4a:16:01:56
|
|
||||||
profile: ovirtmgmt
|
|
||||||
network: ovirtmgmt
|
|
||||||
|
|
||||||
- name: Plug NIC to VM
|
|
||||||
redhat.rhv.ovirt_nic:
|
|
||||||
state: plugged
|
|
||||||
vm: myvm
|
|
||||||
name: mynic
|
|
||||||
|
|
||||||
|
|
||||||
always:
|
|
||||||
- name: Always revoke the SSO token
|
|
||||||
ovirt_auth:
|
|
||||||
state: absent
|
|
||||||
ovirt_auth: "{{ ovirt_auth }}"
|
|
||||||
|
|
||||||
|
|
||||||
# - name: VM Configuration
|
|
||||||
# - name: Automation Platform Installer
|
|
||||||
# - name:
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
- name: Create an ovirt windows template
|
|
||||||
hosts: windows_template_base
|
|
||||||
gather_facts: false
|
|
||||||
connection: local
|
|
||||||
become: false
|
|
||||||
|
|
||||||
vars:
|
|
||||||
ansible_python_interpreter: "{{ ansible_playbook_python }}"
|
|
||||||
|
|
||||||
|
|
||||||
roles:
|
|
||||||
- oatakan.windows_ovirt_template
|
|
||||||
31
playbooks/create_gitea.yml
Normal file
31
playbooks/create_gitea.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
---
|
||||||
|
- name: Create Gitea Server
|
||||||
|
hosts: gitea
|
||||||
|
gather_facts: false
|
||||||
|
|
||||||
|
vars:
|
||||||
|
dnsmadeeasy_hostname: "{{ service_dns_name.split('.') | first }}"
|
||||||
|
dnsmadeeasy_domain: "{{ service_dns_name.split('.',1) |last }}"
|
||||||
|
dnsmadeeasy_record_type: CNAME
|
||||||
|
dnsmadeeasy_record_value: gate.toal.ca.
|
||||||
|
dnsmadeeasy_record_ttl: 600
|
||||||
|
opnsense_service_hostname: "{{ dnsmadeeasy_hostname }}"
|
||||||
|
opnsense_service_domain: "{{ dnsmadeeasy_domain }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Configure DNS
|
||||||
|
ansible.builtin.import_role:
|
||||||
|
name: toallab.infra.dnsmadeeasy
|
||||||
|
tasks_from: provision.yml
|
||||||
|
|
||||||
|
- name: Configure Service
|
||||||
|
ansible.builtin.import_role:
|
||||||
|
name: toallab.infra.opnsense_service
|
||||||
|
tasks_from: provision.yml
|
||||||
|
module_defaults:
|
||||||
|
group/ansibleguy.opnsense.all:
|
||||||
|
firewall: "{{ opnsense_host }}"
|
||||||
|
api_key: "{{ opnsense_api_key }}"
|
||||||
|
api_secret: "{{ opnsense_api_secret }}"
|
||||||
|
ssl_verify: "{{ opnsense_ssl_verify }}"
|
||||||
|
api_port: "{{ opnsense_api_port|default(omit) }}"
|
||||||
6
playbooks/deploy_openshift.yml
Normal file
6
playbooks/deploy_openshift.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: Deploy OpenShift on Proxmox
|
||||||
|
hosts: all
|
||||||
|
gather_facts: false
|
||||||
|
connection: local
|
||||||
|
tasks:
|
||||||
|
|
||||||
@@ -11,7 +11,18 @@
|
|||||||
api_port: "{{ opnsense_api_port|default(omit) }}"
|
api_port: "{{ opnsense_api_port|default(omit) }}"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
# TODO: Clean up subnet / reservation structure
|
- name: Install packages
|
||||||
|
ansibleguy.opnsense.package:
|
||||||
|
name:
|
||||||
|
- os-acme-client
|
||||||
|
action: install
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
- name: Setup ACME Client
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: toallab.infra.opnsense_service
|
||||||
|
tasks_from: setup.yml
|
||||||
|
|
||||||
- name: Configure KEA DHCP Server
|
- name: Configure KEA DHCP Server
|
||||||
ansibleguy.opnsense.dhcp_general:
|
ansibleguy.opnsense.dhcp_general:
|
||||||
enabled: "{{ dhcp_enabled }}"
|
enabled: "{{ dhcp_enabled }}"
|
||||||
@@ -51,5 +62,3 @@
|
|||||||
reload: false
|
reload: false
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
loop: "{{ all_dhcp_reservations }}"
|
loop: "{{ all_dhcp_reservations }}"
|
||||||
|
|
||||||
- name: Add HAProxy
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
hostname, domain, description, enabled, mx, mxprio, prio, record_type, server, value, uuid
|
|
||||||
|
36
vault-id-from-op-client.sh
Executable file
36
vault-id-from-op-client.sh
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
|
# Parse input arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--vault-id)
|
||||||
|
VAULT_ID="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 --vault-id <vault id>" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Validate vault ID
|
||||||
|
if [[ -z "$VAULT_ID" ]]; then
|
||||||
|
echo "Error: Missing required --vault-id argument" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ITEM_NAME="${VAULT_ID} vault key"
|
||||||
|
FIELD_NAME="password"
|
||||||
|
|
||||||
|
# Fetch the vault password from 1Password
|
||||||
|
VAULT_PASSWORD=$(op item get "$ITEM_NAME" --fields "$FIELD_NAME" --format=json --vault LabSecrets 2>/dev/null | jq -r '.value')
|
||||||
|
|
||||||
|
# Output the password or report error
|
||||||
|
if [[ -n "$VAULT_PASSWORD" && "$VAULT_PASSWORD" != "null" ]]; then
|
||||||
|
echo "$VAULT_PASSWORD"
|
||||||
|
else
|
||||||
|
echo "Error: Could not retrieve vault password for vault ID '$VAULT_ID' (item: '$ITEM_NAME')" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user