v1.0
This commit is contained in:
commit
ad75f53a28
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"editor.fontSize": 13,
|
||||
"terminal.integrated.fontSize": 13,
|
||||
"window.zoomLevel": 1.4,
|
||||
}
|
||||
34
LICENSE
Normal file
34
LICENSE
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
Non-Commercial Use License – [sync-awx-inventory.sh]
|
||||
|
||||
Copyright (c) [2025] [Gilles Mouchet]
|
||||
|
||||
This script is provided free of charge with its source code. You are permitted to:
|
||||
|
||||
Use the script for personal, educational, or non-commercial professional purposes.
|
||||
Study, modify, and share the script freely, provided this license is included.
|
||||
|
||||
You are strictly prohibited from:
|
||||
|
||||
- Selling this script or any modified version.
|
||||
- Using it in commercial services or products.
|
||||
- Distributing it in exchange for financial compensation, directly or indirectly.
|
||||
|
||||
This script is provided "as is", without any warranty of any kind.
|
||||
-----------------------------------------------------------------------------------------
|
||||
Licence d’utilisation non commerciale – [sync-awx-inventory.sh]
|
||||
|
||||
Copyright (c) [2025] [Gilles Mouchet]
|
||||
|
||||
Ce script est fourni gratuitement avec son code source. Toute personne est autorisée à :
|
||||
|
||||
Utiliser le script à des fins personnelles, éducatives ou professionnelles non commerciales.
|
||||
Étudier, modifier et partager le script gratuitement, à condition de conserver cette licence.
|
||||
|
||||
Il est strictement interdit de :
|
||||
|
||||
- Vendre ce script ou une version modifiée.
|
||||
- L’utiliser dans des services ou produits commerciaux.
|
||||
- Le distribuer en échange d’une contrepartie financière, directe ou indirecte.
|
||||
|
||||
Ce script est fourni "tel quel", sans garantie d’aucune sorte.
|
||||
40
README.md
Normal file
40
README.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Sync-awx-inventory
|
||||
## Description
|
||||
This script this script synchronize the hosts source file with an AWX inventory
|
||||
|
||||
## Requirements
|
||||
- [Rocky 9 GMo](https://gmodocs.dyndns.org/system/rocky/installation/)
|
||||
- Package
|
||||
- jq
|
||||
|
||||
## Installation
|
||||
### Script
|
||||
```bash
|
||||
cp sync-awx-inventory /usr/local/bin/
|
||||
```
|
||||
|
||||
### AWX credentials
|
||||
Authentication by token. See [](https://ansible.readthedocs.io/projects/awx/en/latest/) to create token
|
||||
```bash
|
||||
cat << EOF > $HOME/.awxcred
|
||||
token=werfgg....drf
|
||||
```
|
||||
|
||||
### Cron
|
||||
```bash
|
||||
echo " */7 * * * * root ./usr/local/bin/sync-awx-inventory.sh > /dev/null 2>&1" > /etc/cron/sync-awx-inventory.cron
|
||||
```
|
||||
|
||||
## Usage
|
||||
```bash
|
||||
sudo /usr/local/bin/sync-awx-inventory.sh --help
|
||||
```
|
||||
## Logs
|
||||
```bash
|
||||
sudo journalctl -f -t syn_awx_inv
|
||||
```
|
||||
|
||||
## Changelog
|
||||
#### [1.0] - 29.05.2025
|
||||
##### Added
|
||||
- Version from scratch by [GMo](mailto:gilles.mouchet@gmail.com)
|
||||
257
sync-awx-inventory.sh
Executable file
257
sync-awx-inventory.sh
Executable file
@ -0,0 +1,257 @@
|
||||
#!/bin/bash
|
||||
############################################################
|
||||
# Decription: this script synchronize the hosts source
|
||||
# file with an AWX inventory
|
||||
#
|
||||
# Author: Gilles Mouchet (gilles.mouchet@gmail.com)
|
||||
# Creation Date: 29.05.2025
|
||||
# Version: 1.0
|
||||
#
|
||||
# Install: see README.md
|
||||
# Usage: ./sync-awx-inventory.sh --help
|
||||
# Changelog:
|
||||
# V1.0 - 29.05.2025 - GMo
|
||||
# Added
|
||||
# - Creation of script from scratch
|
||||
#
|
||||
############################################################
|
||||
|
||||
version=1.0
|
||||
#user=user_name
|
||||
#pass=secret
|
||||
cred_file=$HOME/.awxcred
|
||||
|
||||
# awx server
|
||||
awx_srv=awx
|
||||
awx_srv_url=https://${awx_srv}.gmolab.net
|
||||
|
||||
# awx inventory name
|
||||
awx_inventory=linux
|
||||
|
||||
# search domain in hosts file
|
||||
search_domain=gmolab
|
||||
search_domain_prefix=net
|
||||
|
||||
# hosts file
|
||||
src_hosts_file=/etc/hosts
|
||||
log_tag=syn_awx_inv
|
||||
|
||||
# array of host name in /etc/hosts
|
||||
hosts_array=()
|
||||
|
||||
#----- FUNCTIONS -----#
|
||||
# function add host in awx inventory
|
||||
add_host_in_awx() { #inventories/{id}/hosts/
|
||||
api_rc=$(curl -s -o /dev/null -w "%{http_code}" -X POST "$awx_srv_url/api/v2/hosts/" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $awx_token" \
|
||||
-d @- <<EOF
|
||||
{
|
||||
"name": "$1",
|
||||
"inventory": $inventory_id
|
||||
}
|
||||
EOF
|
||||
)
|
||||
#echo $api_rc
|
||||
return $api_rc
|
||||
}
|
||||
|
||||
# function delete host from AWX inventory
|
||||
del_host_from_awx() {
|
||||
# get host id
|
||||
host_id=$(curl -s -H "Authorization: Bearer $awx_token" \
|
||||
"$awx_srv_url/api/v2/inventories/$inventory_id/hosts/?name=$1" | jq -r '.results[0].id')
|
||||
|
||||
# check if host exist in inventory
|
||||
if [[ "$host_id" == "null" || -z "$host_id" ]]; then
|
||||
msg="'$1' not found in inventory id."
|
||||
echo ${msg}; logger -t $log_tag ${msg}
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# delete host
|
||||
api_rc=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
|
||||
-H "Authorization: Bearer $awx_token" \
|
||||
"$awx_srv_url/api/v2/hosts/$host_id/")
|
||||
return $api_rc
|
||||
}
|
||||
#--------------------------#
|
||||
# END FUNCTION #
|
||||
#--------------------------#
|
||||
#--------------------------#
|
||||
# MAIN #
|
||||
#--------------------------#
|
||||
|
||||
# display stdout and stderr on screen and on log
|
||||
# to read log use sudo "journalctl -f -t syn_awx_inv" command
|
||||
exec > >(tee /dev/tty | logger -t $log_tag)
|
||||
exec 2> >(tee /dev/tty >&2 | logger -t $log_tag)
|
||||
|
||||
case $1 in
|
||||
-p|--parameter)
|
||||
cat << EOF
|
||||
Credentials file (\$cred_file): $cred_file
|
||||
Source file (\$src_hosts_file): $src_hosts_file
|
||||
AWX inventory (\$awx_inventory): $awx_inventory
|
||||
Domain search in src (\$search_domain): $search_domain.$search_domain_prefix
|
||||
AWX server url (\$awx_srv_url): $awx_srv_url
|
||||
Log tag (\$log_tag): $log_tag
|
||||
EOF
|
||||
exit 1
|
||||
;;
|
||||
-h|--help)
|
||||
cat << EOF
|
||||
Usage: $(basename "$0") OPTIONS
|
||||
Synchronizes the hosts source file with an AWX inventory
|
||||
Options:
|
||||
-p, --parameter display parameters
|
||||
-l, --help display this help text and exit
|
||||
-v, --version display the verion
|
||||
EOF
|
||||
exit
|
||||
;;
|
||||
-v|--version)
|
||||
cat << EOF
|
||||
$(basename "$0") v$version (c) 1990 - $(date +%Y) by Gilles Mouchet
|
||||
Non-Commercial Use License – See LICENSE for details
|
||||
EOF
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
logger -t $log_tag "[INFO] - start script"
|
||||
#check if awx server is up
|
||||
if ! nc -z -w 2 $awx_srv 22 2>/dev/null; then
|
||||
echo "[ERROR] - server '$awx_srv_url' is not up"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# read awx credential
|
||||
if [ -f $cred_file ]; then
|
||||
awx_token=$(grep "token=" $cred_file | cut -d'=' -f2)
|
||||
else
|
||||
echo "[ERROR] - file $cred_file not found !"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#---------- create host list from inventory
|
||||
# get inventory id
|
||||
inventory_id=$(curl -s -H "Authorization: Bearer $awx_token" \
|
||||
"$awx_srv_url/api/v2/inventories/?name=$awx_inventory"| jq -r '.results[0].id')
|
||||
|
||||
# get inventory items
|
||||
# this curl display onliy the 25 first host (pagination)
|
||||
#awx_item=$(curl -s -H "Authorization: Bearer $awx_token" \
|
||||
# "$awx_srv_url/api/v2/inventories/$inventory_id/hosts/")
|
||||
|
||||
# this get ALL hosts in inventory
|
||||
next_url="$awx_srv_url/api/v2/inventories/$inventory_id/hosts/"
|
||||
while [ -n "$next_url" ] && [ "$next_url" != "null" ]; do
|
||||
awx_item=$(curl -s -H "Authorization: Bearer $awx_token" -H "Accept: application/json" "$next_url")
|
||||
|
||||
# extract hostnames and add them to the table
|
||||
mapfile -t new_hosts < <(echo "$awx_item" | jq -r '.results[].name')
|
||||
hosts_in_awx+=("${new_hosts[@]}")
|
||||
|
||||
next_url=$(echo "$awx_item" | jq -r '.next')
|
||||
# complete the URL if necessary
|
||||
if [[ "$next_url" =~ ^/ ]]; then
|
||||
next_url="$awx_srv_url$next_url"
|
||||
fi
|
||||
done
|
||||
|
||||
#---------- create host list from hosts file
|
||||
# read hosts fiée
|
||||
while IFS= read -r line; do
|
||||
hosts_in_file+=("$line")
|
||||
done < <( grep -v '^#' $src_hosts_file \
|
||||
| sed 's/#.*//' \
|
||||
| tr -s ' ' \
|
||||
| tr '\t' ' ' \
|
||||
| cut -d ' ' -f2- \
|
||||
| tr ' ' '\n' \
|
||||
| grep '\.'$search_domain'\.'$search_domain_prefix'$' \
|
||||
| sed 's/\.'$search_domain'\.'$search_domain_prefix'$//' \
|
||||
| sort -u
|
||||
)
|
||||
#
|
||||
# for debug only
|
||||
# test for pagination 30 hosts
|
||||
#hosts_in_file=(titi gros-minet tom jerry cortex minus road-runner coyote bugs-bunny riri fifi loulou picsou \
|
||||
# donald-duck mickey pluto mister-magoo droopy calimero scooby-doo samy daffy-duck popey \
|
||||
# woody-woodpecker garfield casper winnie casper homer marge bart)
|
||||
# test for pagination 25 hosts
|
||||
#hosts_in_file=(titi gros-minet tom jerry cortex minus road-runner coyote bugs-bunny fifi loulou picsou \
|
||||
# donald-duck mickey scooby-doo samy daffy-duck popey \
|
||||
# woody-woodpecker garfield casper winnie casper homer marge bart)
|
||||
|
||||
# CAUTION delete all host in AWX inventory
|
||||
#hosts_in_file=()
|
||||
|
||||
#---------- add host in awx inventory if not exixts
|
||||
echo "[INFO] - add host to '$awx_inventory' AWX inventory"
|
||||
action_add=false
|
||||
# loop on each element of the source host file
|
||||
for item_host in "${hosts_in_file[@]}"; do
|
||||
found=false
|
||||
# loop on each item from awx inventory
|
||||
for item_awx in "${hosts_in_awx[@]}"; do
|
||||
# check if host in source exist in awx inventoy
|
||||
if [[ "$item_host" == "$item_awx" ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
# if not found, add host into awx inventory
|
||||
if ! $found; then
|
||||
action_add=true
|
||||
add_host_in_awx $item_host
|
||||
rc=$?
|
||||
if [ "$rc" -eq "201" ]; then
|
||||
echo "[SUCCESS] - host '$item_host' successfully added to '$awx_inventory' AWX inventory"
|
||||
else
|
||||
echo "[ERROR] - error $rc when adding '$item_host' to '$awx_inventory' AWX inventory"
|
||||
#exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if ! $action_add; then
|
||||
echo "[INFO] - no hosts added to AWX '$awx_inventory' inventory"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
#---------- check if hosts from awx exist in the source host file
|
||||
#---------- if not, delete from awx inventory
|
||||
echo "[INFO] - delete host from '$awx_inventory' AWX inventory"
|
||||
action_del=false
|
||||
# loop on each item from awx inventory
|
||||
for item_awx in "${hosts_in_awx[@]}"; do
|
||||
found=false
|
||||
# loop on each element of the source host file
|
||||
for item_host in "${hosts_in_file[@]}"; do
|
||||
# check if host in awx inventory exist in the source host file
|
||||
if [[ "$item_awx" == "$item_host" ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
# if not found, delete host from awx inventory
|
||||
if ! $found; then
|
||||
action_del=true
|
||||
del_host_from_awx $item_awx
|
||||
rc=$?
|
||||
if [[ "$rc" == "204" ]]; then
|
||||
echo "[SUCCESS] - host '$item_awx' successfully deleted from '$awx_inventory' inventory"
|
||||
else
|
||||
echo "[ERROR] - error $rc when deleting '$item_awx' from '$awx_inventory' AWX inventory"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if ! $action_del; then
|
||||
echo "[INFO] - no host to delete from '$awx_inventory AWX inventory"
|
||||
fi
|
||||
echo ""
|
||||
echo "[INFO] - the '$awx_inventory' inventory on AWX is up to date"
|
||||
logger -t $log_tag "[INFO] - start script"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user