commit a1b2b4dd8ff44a5dd5baf78466f63a64d4b81a3e Author: jerick Date: Fri Mar 13 08:38:01 2026 -0400 first commit diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..bda145c --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,68 @@ +pipeline { + agent any + + parameters { + string( + name: 'LIMIT', + defaultValue: '', + description: 'Limit to specific hosts or groups (e.g., "vms", "lxcs", "zabbix", or hostname) no .lan required' + ) + booleanParam( + name: 'DRY_RUN', + defaultValue: false, + description: 'Run in check mode — no changes will be applied to target hosts' + ) + } + + environment { + PROXMOX_URL = 'https://192.168.0.166:8006' + PROXMOX_USER = 'dynamic-inventory@pve' + PROXMOX_TOKEN_ID = 'dynamic-inventory' + PROXMOX_TOKEN_SECRET = credentials('PROXMOX_TOKEN_SECRET') + ANSIBLE_HOST_KEY_CHECKING = 'False' + } + + stages { + stage('Checkout') { + steps { + checkout scm + } + } + + stage('Verify Inventory') { + steps { + sh ''' + echo "Testing dynamic inventory connection..." + ansible-inventory -i inventory/inventory.proxmox.yml --list | head -10 + ''' + } + } + + stage('Run Playbook') { + steps { + script { + def limitFlag = params.LIMIT ? "--limit '${params.LIMIT}'" : '' + def checkFlag = params.DRY_RUN ? '--check --diff' : '' + + sh """ + ansible-playbook \ + -i inventory/inventory.proxmox.yml \ + playbooks/install_zabbix.yml \ + ${limitFlag} \ + ${checkFlag} \ + -v + """ + } + } + } + } + + post { + success { + echo "Zabbix agent installation completed successfully" + } + failure { + echo "Zabbix agent installation failed" + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..3a7ca14 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +# zabbix-agent-install + +Ansible playbook and Jenkins pipeline for installing Zabbix Agent2 on Proxmox-hosted VMs and LXC containers. Hosts are discovered automatically via the Proxmox dynamic inventory plugin based on Proxmox tags — no manual inventory management required. + +## How it works + +1. Jenkins triggers the pipeline with a Proxmox tag as a parameter (default: `zabbix`). +2. The Proxmox dynamic inventory plugin queries the Proxmox API and discovers all VMs/LXCs with that tag. +3. Ansible connects to those hosts via SSH and runs the `zabbix_agent` role to install and configure Zabbix Agent2. + +## Prerequisites + +### On Proxmox hosts (target VMs/LXCs) +- Ubuntu 24.04 (the role installs the `ubuntu24.04` release package by default) +- QEMU guest agent installed and running — required for automatic IP address discovery +- SSH accessible by the Ansible user +- Tagged in Proxmox with the tag used to filter (e.g. `zabbix`) + +### On the Ansible control node / Jenkins agent +- Ansible >= 2.14 +- Python 3 +- `community.general` collection >= 8.0.0 — install once on the agent: + ```bash + ansible-galaxy collection install -r requirements.yml + ``` + +## Jenkins setup + +### Credentials + +| Credential ID | Type | Description | +|--------------------|-----------------------|-------------| +| `proxmox-api-token` | Secret text | Proxmox API token in the format `user@realm!tokenid=secret` | +| `ansible-ssh-key` | SSH username with key | SSH key used by Ansible to connect to target hosts | + +The Proxmox API token needs at minimum `VM.Audit` and `VM.Config.Network` permissions to read VM data from the API. + +### Pipeline parameters + +| Parameter | Default | Description | +|-----------------|--------------|-------------| +| `PROXMOX_TAG` | `zabbix` | Proxmox tag used to select target hosts | +| `ZABBIX_SERVER` | `zabbix.lan` | Hostname or IP of the Zabbix server | +| `ZABBIX_VERSION`| `7.0` | Zabbix agent2 version to install | +| `DRY_RUN` | `false` | Run in `--check --diff` mode without making changes | + +## Project structure + +``` +zabbix-agent-install/ +├── Jenkinsfile # CI/CD pipeline definition +├── ansible.cfg # Ansible configuration +├── requirements.yml # Ansible Galaxy collection dependencies +├── inventory/ +│ ├── proxmox.yml # Proxmox dynamic inventory plugin config +│ └── hosts.yml # (legacy static inventory, not used by pipeline) +├── playbooks/ +│ └── install_zabbix.yml # Main playbook — targets tagged hosts +└── roles/ + └── zabbix_agent/ + ├── defaults/ + │ └── main.yml # Default role variables + └── tasks/ + └── main.yml # Installation and configuration tasks +``` + +## Role variables + +Defined in [roles/zabbix_agent/defaults/main.yml](roles/zabbix_agent/defaults/main.yml): + +| Variable | Default | Description | +|------------------------|-----------|-------------| +| `zabbix_server` | `zabbix.lan` | Zabbix server address (passive and active checks) | +| `zabbix_version` | `7.0` | Zabbix repository version | +| `zabbix_release` | `7.0-2` | Exact release package version (update if changing major version) | +| `zabbix_ubuntu_version`| `24.04` | Ubuntu version for the release package URL | + +## Dynamic inventory + +The [inventory/proxmox.yml](inventory/proxmox.yml) file configures the `community.general.proxmox` inventory plugin. It reads credentials from environment variables set by the Jenkins pipeline: + +| Variable | Description | +|------------------------|-------------| +| `PROXMOX_URL` | Proxmox API URL (default: `https://proxmox.lan:8006`) | +| `PROXMOX_USER` | API user (e.g. `ansible@pam`) | +| `PROXMOX_TOKEN_ID` | API token ID | +| `PROXMOX_TOKEN_SECRET` | API token secret | + +Proxmox tags are automatically mapped to Ansible groups with the prefix `proxmox_tag_`. A VM tagged `zabbix` will appear in the group `proxmox_tag_zabbix`, which is the group targeted by the playbook. + +### Running the inventory manually + +```bash +export PROXMOX_USER="ansible@pam" +export PROXMOX_TOKEN_ID="mytoken" +export PROXMOX_TOKEN_SECRET="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + +# List all discovered hosts +ansible-inventory -i inventory/proxmox.yml --list + +# Show hosts in the zabbix tag group +ansible-inventory -i inventory/proxmox.yml --graph proxmox_tag_zabbix +``` + +## Running the playbook manually + +```bash +export PROXMOX_USER="ansible@pam" +export PROXMOX_TOKEN_ID="mytoken" +export PROXMOX_TOKEN_SECRET="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + +# Install Zabbix agent on all hosts tagged "zabbix" +ansible-playbook playbooks/install_zabbix.yml \ + -i inventory/proxmox.yml \ + -u ansible \ + --private-key ~/.ssh/id_ed25519 \ + -e "proxmox_filter_tag=zabbix" \ + -e "zabbix_server=zabbix.lan" \ + -e "zabbix_version=7.0" + +# Dry run (no changes applied) +ansible-playbook playbooks/install_zabbix.yml \ + -i inventory/proxmox.yml \ + -u ansible \ + --private-key ~/.ssh/id_ed25519 \ + -e "proxmox_filter_tag=zabbix" \ + --check --diff +``` diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..4f597ef --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = ./inventory/inventory.proxmox.yml +roles_path = ./roles +host_key_checking = False +retry_files_enabled = False +gathering = smart +fact_caching = memory + +[ssh_connection] +pipelining = True +ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null diff --git a/inventory/inventory.proxmox.yml b/inventory/inventory.proxmox.yml new file mode 100644 index 0000000..c0c9e63 --- /dev/null +++ b/inventory/inventory.proxmox.yml @@ -0,0 +1,26 @@ +# Proxmox Dynamic Inventory +# Requires PROXMOX_TOKEN_SECRET environment variable to be set +plugin: community.proxmox.proxmox +url: https://192.168.0.166:8006 +user: dynamic-inventory@pve +token_id: dynamic-inventory +validate_certs: false +want_facts: true + +# Filter to only running machines +filters: + - proxmox_status == 'running' + +# Group by Proxmox tags and type +groups: + vms: "'qemu' in proxmox_type" + lxcs: "'lxc' in proxmox_type" + # Tag-based groups - add tags in Proxmox to auto-group + update_targets: "'update' in (proxmox_tags | default([]))" + docker_hosts: "'docker' in (proxmox_tags | default([]))" + kubernetes: "'k8s' in (proxmox_tags | default([]))" + zabbix: "'zabbix' in (proxmox_tags | default([]))" + +compose: + ansible_host: name + '.lan' + ansible_user: 'jenkins' diff --git a/playbooks/install_zabbix.yml b/playbooks/install_zabbix.yml new file mode 100644 index 0000000..b5d5995 --- /dev/null +++ b/playbooks/install_zabbix.yml @@ -0,0 +1,8 @@ +--- +- name: Install Zabbix Agent2 on tagged Proxmox hosts + hosts: zabbix + become: true + gather_facts: true + + roles: + - zabbix_agent diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..3c194cf --- /dev/null +++ b/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: community.general + version: ">=8.0.0" diff --git a/roles/zabbix_agent/defaults/main.yml b/roles/zabbix_agent/defaults/main.yml new file mode 100644 index 0000000..ecaa019 --- /dev/null +++ b/roles/zabbix_agent/defaults/main.yml @@ -0,0 +1,5 @@ +--- +zabbix_server: "zabbix.lan" +zabbix_version: "7.0" +zabbix_release: "7.0-2" +zabbix_ubuntu_version: "24.04" diff --git a/roles/zabbix_agent/tasks/main.yml b/roles/zabbix_agent/tasks/main.yml new file mode 100644 index 0000000..ca983d5 --- /dev/null +++ b/roles/zabbix_agent/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- name: Get Ubuntu codename + ansible.builtin.command: lsb_release -cs + register: ubuntu_codename + changed_when: false + +- name: Download Zabbix repository package + ansible.builtin.get_url: + url: "https://repo.zabbix.com/zabbix/{{ zabbix_version }}/ubuntu/pool/main/z/zabbix-release/zabbix-release_{{ zabbix_release }}+ubuntu{{ zabbix_ubuntu_version }}_all.deb" + dest: /tmp/zabbix-release.deb + mode: '0644' + +- name: Install Zabbix repository package + ansible.builtin.apt: + deb: /tmp/zabbix-release.deb + +- name: Install Zabbix agent2 + ansible.builtin.apt: + name: zabbix-agent2 + state: present + update_cache: true + +- name: Configure Zabbix server address + ansible.builtin.lineinfile: + path: /etc/zabbix/zabbix_agent2.conf + regexp: '^Server=' + line: "Server={{ zabbix_server }}" + +- name: Configure Zabbix active server address + ansible.builtin.lineinfile: + path: /etc/zabbix/zabbix_agent2.conf + regexp: '^ServerActive=' + line: "ServerActive={{ zabbix_server }}" + +- name: Configure Zabbix agent hostname + ansible.builtin.lineinfile: + path: /etc/zabbix/zabbix_agent2.conf + regexp: '^Hostname=' + line: "Hostname={{ ansible_hostname }}" + +- name: Enable and start Zabbix agent2 + ansible.builtin.systemd: + name: zabbix-agent2 + state: started + enabled: true + daemon_reload: true