Skip to content

Commit

Permalink
proper install script
Browse files Browse the repository at this point in the history
  • Loading branch information
lfkdev committed Jul 1, 2024
1 parent fa2f660 commit 5f59617
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 59 deletions.
18 changes: 7 additions & 11 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
- Added install script

#### **Thread Safety** 🔒
- Jobs are now also being saved to disk
- `/jobs` endpoint now pulls all infos from saved JSON files
- (potentially **BREAKING**) saved jobs now only use their UUID as name (`jq` can be used to filter easily)

#### **WSGI** 🌐
- Minor import refactor
- WSGI default file
- changed README for gunicorn
#### General 🚀
- Install script now sets up a production-ready installation of ansible-link
- Fetches the latest version of ansible-link from GitHub
- Includes Gunicorn for handling requests
- Configures Unix sockets for communication
- Sets up a Python virtual environment (venv)
- Updated README for install script instructions
57 changes: 31 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,34 +28,33 @@
Searched for a way to run our playbooks automated without the need of AWX or other big projects while still being more stable and less error-prone than custom bash scripts. So I made Ansible-Link. This projects aims to be a KISS way to run ansible jobs remotely. Essentially a RESTful API sitting on top of [ansible-runner](https://github.com/ansible/ansible-runner).

## Prerequisites
* Python 3.7+
* PIP
* Your Ansible node

## Installation
* Clone the repository (on your ansible-node):
```shell
git clone [email protected]:lfkdev/ansible-link.git
cd ansible-link
```
The fastest way to set up Ansible-Link is by using the provided `install.sh` script:

* Install the dependencies:
```shell
# use virtual env
pip install -r requirements.txt
```
1. **Download and run the install script:**
```shell
wget https://raw.githubusercontent.com/lfkdev/ansible-link/main/install.sh -O - | sudo bash
```

This script will:
- Check for necessary dependencies and install them if missing.
- Download and install Ansible-Link.
- Set up a Python virtual environment.
- Configure a systemd service for Ansible-Link.

After the installation, you can start using Ansible-Link immediately. You probably need to change some config values for your ansible environment `/opt/ansible-link/config.yml`

* Set config values in `config.yml`
```yaml
playbook_dir: '/etc/ansible/'
inventory_file: '/etc/ansible/environments/hosts'
...
```

* Start Ansible-Link
```shell
python3 ansible_link/ansible_link.py
```
The API will be accessible at localhost:port (default 5001) or wherever you bind it to.
To add more workers or change the user, modify `/etc/systemd/system/ansible-link.service`
> ⚠️ **Note:** Currently, only Ubuntu versions 16.04 and higher, or Debian versions 9 and higher are officially supported.
> Other operating systems might also work but have not been tested. You can clone the repository and perform a manual installation if you are using a different OS.

## API Documentation
The API documentation is available via the Swagger UI.
Expand Down Expand Up @@ -128,20 +127,26 @@ Leave empty to allow all playbooks. This is for the backend, you could also use

## Prod environment

**Use WSGI for prod ENV (gunicorn) + systemd service**
You can use the install script `install.sh` to get a production-ready environment for Ansible-Link.

The install script will:
- Set up a Python VENV
- Configure a systemd service to manage Ansible-Link
- Utilize Gunicorn as the WSGI server.

You can use a webserver like Caddy to add Basic Authentication and TLS to your Ansible-Link setup.

### unitd example file
### unitD example
```
[Unit]
Description=Ansible Link
Description=Ansible Link Service
After=network.target
[Service]
User=ansible
Group=ansible
WorkingDirectory=/opt/ansible-link
ExecStart=/usr/local/bin/gunicorn -w 1 -k gthread -b localhost:5000 wsgi:app
Restart=on-failure
ExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind unix:$INSTALL_DIR/ansible_link.sock -m 007 wsgi:application
WorkingDirectory=$INSTALL_DIR
Restart=always
User=root
[Install]
WantedBy=multi-user.target
Expand Down
98 changes: 77 additions & 21 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,50 @@ log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')][$1] $2"
}

display_header() {
cat << "EOF"
_____ _ _ _ __ _ _
| _ |___ ___|_| |_| |___ ___| | |_|___| |_
| | |_ -| | . | | -_|___| |__| | | '_|
|__|__|_|_|___|_|___|_|___| |_____|_|_|_|_,_|
EOF
echo " $ANSIBLE_LINK_VERSION | github.com/lfkdev/ansible-link"
echo
}

get_latest_version() {
LATEST_VERSION=$(curl -s https://api.github.com/repos/lfkdev/ansible-link/releases/latest | grep -Po '"tag_name": "\K.*?(?=")' | sed 's/^v//')
if [[ -z "$LATEST_VERSION" ]]; then
log "ERROR" "Failed to fetch the latest version. Using default version $ANSIBLE_LINK_VERSION."
else
ANSIBLE_LINK_VERSION="$LATEST_VERSION"
log "INFO" "Latest version is $ANSIBLE_LINK_VERSION."
fi
}

check_root() {
if [[ $EUID -ne 0 ]]; then
log "ERROR" "This script must be run as root"
log "ERROR" "This script must be run as root"
exit 1
fi
}

check_existing_installation() {
if [[ -d "$INSTALL_DIR" ]]; then
read -p "ansible-link is already installed. Do you want to reinstall? (y/N) " -n 1 -r
read -p "ansible-link is already installed. Do you want to reinstall? This will delete $INSTALL_DIR. (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
if [[ $REPLY =~ ^[Yy]$ ]]; then
log "INFO" "Stopping ansible-link service..."
if systemctl list-units --full -all | grep -Fq 'ansible-link.service'; then
systemctl stop ansible-link
systemctl disable ansible-link
log "INFO" "ansible-link service stopped and disabled."
fi
log "INFO" "Removing existing installation..."
if [[ -n "$INSTALL_DIR" ]]; then
rm -rf "${INSTALL_DIR:?}"
fi
else
log "INFO" "Installation cancelled."
exit 0
fi
Expand All @@ -39,23 +71,22 @@ check_systemd() {

install_dependencies() {
log "INFO" "Installing dependencies..."
apt-get update
apt-get install -y python3 python3-venv python3-pip unzip
apt-get update -qq
apt-get install -y -qq python3 python3-venv python3-pip unzip
}

download_ansible_link() {
log "INFO" "Downloading ansible-link..."
mkdir -p "$TEMP_DIR"
wget "https://github.com/lfkdev/ansible-link/releases/download/v${ANSIBLE_LINK_VERSION}/ansible-link-${ANSIBLE_LINK_VERSION}.zip" -O "$TEMP_DIR/ansible-link.zip"
wget -q "https://github.com/lfkdev/ansible-link/releases/download/v${ANSIBLE_LINK_VERSION}/ansible-link-${ANSIBLE_LINK_VERSION}.zip" -O "$TEMP_DIR/ansible-link.zip"
unzip -o "$TEMP_DIR/ansible-link.zip" -d "$TEMP_DIR"
}

install_ansible_link() {
log "INFO" "Installing ansible-link..."
mkdir -p "$INSTALL_DIR"
mv "$TEMP_DIR/config.yml" "$TEMP_DIR/ansible_link.py" "$TEMP_DIR/webhook.py" "$TEMP_DIR/version.py" "$INSTALL_DIR/"
mv "$TEMP_DIR"/*.py "$TEMP_DIR"/*.yml "$INSTALL_DIR/"
}

setup_venv() {
log "INFO" "Setting up virtual environment..."
python3 -m venv "$VENV_DIR"
Expand All @@ -64,12 +95,17 @@ setup_venv() {

install_python_requirements() {
log "INFO" "Installing Python requirements in virtual environment..."
"$VENV_DIR/bin/pip" install -r "$TEMP_DIR/requirements.txt"
"$VENV_DIR/bin/pip" install --upgrade pip --quiet
"$VENV_DIR/bin/pip" install 'importlib-metadata<6.3,>=4.6' --quiet # importlib ubuntu 22 workaround
"$VENV_DIR/bin/pip" install -r "$TEMP_DIR/requirements.txt" --quiet
"$VENV_DIR/bin/pip" install gunicorn --quiet
}

cleanup() {
log "INFO" "Cleaning up..."
rm -rf "$TEMP_DIR"
if [[ -d "$TEMP_DIR" ]]; then
rm -r "${TEMP_DIR:?}"
fi
}

detect_ansible() {
Expand Down Expand Up @@ -101,7 +137,7 @@ Description=Ansible Link Service
After=network.target
[Service]
ExecStart=$VENV_DIR/bin/python3 $INSTALL_DIR/ansible_link.py
ExecStart=$VENV_DIR/bin/gunicorn --workers 1 --bind unix:$INSTALL_DIR/ansible_link.sock -m 007 wsgi:application
WorkingDirectory=$INSTALL_DIR
Restart=always
User=root
Expand All @@ -115,16 +151,35 @@ EOL
systemctl start ansible-link.service
}

main() {
log "INFO" "Preparing to install ansible-link version $ANSIBLE_LINK_VERSION..."

download_ansible_link
check_os_version() {
if [[ -f /etc/os-release ]]; then
. /etc/os-release
if [[ "$ID" == "ubuntu" && "$VERSION_ID" < "16.04" ]]; then
log "ERROR" "Ubuntu version must be at least 16.04. Detected version: $VERSION_ID"
exit 1
elif [[ "$ID" == "debian" && "$VERSION_ID" < "9" ]]; then
log "ERROR" "Debian version must be at least 9. Detected version: $VERSION_ID"
exit 1
elif [[ "$ID" != "ubuntu" && "$ID" != "debian" ]]; then
log "ERROR" "Unsupported OS. Only Ubuntu and Debian are supported."
exit 1
fi
else
log "ERROR" "Cannot determine OS version. /etc/os-release not found."
exit 1
fi
}

echo "This script will install (if not already) the following:"
echo "- Python 3, python3-venv, pip"
echo "- ansible-link in $INSTALL_DIR"
echo "- A systemd service for ansible-link"

main() {
echo
check_os_version
get_latest_version
display_header
echo "This script will ensure your system is set up with the following components:"
echo "1. Python 3, python3-venv, and pip"
echo -e "2. Ansible-Link installed in the directory: \e[32m$INSTALL_DIR\e[0m"
echo "3. A SystemD service for Ansible-Link utilizing Gunicorn"
echo
read -p "Do you want to proceed with the installation? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
Expand All @@ -137,6 +192,7 @@ main() {
check_existing_installation
check_systemd
install_dependencies
download_ansible_link
install_ansible_link
setup_venv
install_python_requirements
Expand All @@ -149,7 +205,7 @@ main() {
log "INFO" "The service is running and will start automatically on boot. ✔"
log "INFO" "You can check the status with: systemctl status ansible-link. ✔"
log "WARN" "Ansible user defaults to root. ⚠"
log "INFO" "Please check the configuration and if needed change the default values in $INSTALL_DIR/config.yml. ⚠"
log "INFO" "Please check the configuration and if needed change the default values in $INSTALL_DIR/config.yml. ⚠"
}

main
2 changes: 1 addition & 1 deletion src/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = "2.1.1"
VERSION = "2.1.2"

def get_version():
return VERSION

0 comments on commit 5f59617

Please sign in to comment.