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": [
|
||||
"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/ansible_collections/,target=/workspaces/collections/,type=bind,consistency=cached",
|
||||
]
|
||||
}
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -107,7 +107,14 @@ venv.bak/
|
||||
|
||||
# Ansible
|
||||
*.retry
|
||||
ansible-navigator.log
|
||||
.ansible/
|
||||
|
||||
# Vendor roles (install via roles/requirements.yml)
|
||||
roles/geerlingguy.*
|
||||
roles/oatakan.*
|
||||
roles/ikke_t.*
|
||||
roles/sage905.*
|
||||
|
||||
.vscode/
|
||||
keys/
|
||||
|
||||
@@ -3,3 +3,26 @@ repos:
|
||||
rev: v8.18.2
|
||||
hooks:
|
||||
- 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) }}"
|
||||
|
||||
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
|
||||
ansibleguy.opnsense.dhcp_general:
|
||||
enabled: "{{ dhcp_enabled }}"
|
||||
@@ -51,5 +62,3 @@
|
||||
reload: false
|
||||
delegate_to: localhost
|
||||
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