diff --git a/local-app/python-tools/build-ansible-distribution/README.md b/local-app/python-tools/build-ansible-distribution/README.md new file mode 100644 index 00000000..007ede6a --- /dev/null +++ b/local-app/python-tools/build-ansible-distribution/README.md @@ -0,0 +1,56 @@ +# Portable Ansible Distribution + +A self-contained Ansible environment built with `uv`, designed to be packaged as a tarball and deployed to systems with minimal dependencies. + +## Architecture +- **Root**: `/apps/ansible` +- **Binaries**: Located in `/apps/ansible/bin` (Symlinked to `.venv/bin`) +- **Python**: Bundled Python 3.13 interpreter (isolated from system Python). +- **Isolation**: Uses `--link-mode copy` to ensure no dependencies on the local `uv` cache. + +## Usage + +### Deployment +1. Tar the directory: `tar -czvf ansible-dist.tar.gz /apps/ansible` +2. Extract on target: `tar -xzvf ansible-dist.tar.gz -C /` +3. Load path: `source /etc/profile.d/ansible.sh` + +### Adding Packages +To add new Python dependencies or Ansible collections: +```bash +cd /apps/ansible +uv add --link-mode copy +``` + +## Profile Configuration + +To enable this globally, run: + +```bash +sudo cp /apps/ansible/ansible_path.sh /etc/profile.d/ansible.sh +sudo chmod +x /etc/profile.d/ansible.sh +``` + +OR + +```bash +sudo ln -sf /apps/ansible/ansible_path.sh /etc/profile.d/ansible.sh +``` + +## Portability Notes + +* **Relocatable Mode**: When enabled, shebangs use `#!/usr/bin/env python`. +* **Paths**: If `MAKE_RELOCATABLE` is 0, the distribution must reside in `/apps/ansible`. + + +# CHANGELOG + +| Version | Description | +| --- | --- | +| **1.0.5** | Added `MAKE_RELOCATABLE` toggle. Added `/etc/profile.d` path script generation. | +| **1.0.4** | Replaced `--copy-python` with physical binary replacement for `uv 0.5+` compatibility. | +| **1.0.3** | Switched to `dependency-groups` to resolve `tool.uv.dev-dependencies` deprecation. | +| **1.0.2** | Implemented `--link-mode copy` to prevent symlinking to user home directory. | +| **1.0.1** | Initial `uv` integration with Python 3.13 and symlinked `bin` directory. | +| **1.0.0** | Basic project structure and `pyproject.toml` initialization. | + diff --git a/local-app/python-tools/build-ansible-distribution/create-ansible.sh b/local-app/python-tools/build-ansible-distribution/create-ansible.sh index d93c656a..488147c8 100755 --- a/local-app/python-tools/build-ansible-distribution/create-ansible.sh +++ b/local-app/python-tools/build-ansible-distribution/create-ansible.sh @@ -1,95 +1,80 @@ #!/bin/bash -VERSION="1.0.3" -THIS=$(basename $0 .sh) +# --- Configuration --- +APP_DIR="/apps/ansible" +PYTHON_VERSION="3.13" +MAKE_RELOCATABLE=0 +VERSION="1.0.5" +# --------------------- -# Define the target directory -if [ -z "$1" ] +THIS=$(basename $0 .sh) +if [ ! -z "$1" ] then - APP_DIR="/apps/ansible" -else APP_DIR="$1" fi -PYTHON_VERSION="3.13" # Can be changed to 3.12 or latest -MAKE_RELOCATABLE=0 # Set to 1 to patch shebangs for any-path portability +echo "Initializing Ansible Distribution v$VERSION..." -# 0. export environment variables needed -export SSL_CERT_FILE=/etc/pki/tls/certs/ca-bundle.crt -#export UV_PYTHON_INSTALL_DIR=/apps/uv/share -export UV_LINK_MODE=copy -export UV_NATIVE_TLS=true - -# 1. Create and enter the directory -mkdir -p "$APP_DIR" -chown $(whoami):$(whoami) "$APP_DIR" +# 1. Prepare Directory +sudo mkdir -p "$APP_DIR" +sudo chown $(whoami):$(whoami) "$APP_DIR" cd "$APP_DIR" -# 2. Initialize the uv project +# 2. Initialize project uv init --no-workspace --app -# 3. Create the pyproject.toml with Ansible dependencies +# 3. Create pyproject.toml cat < pyproject.toml [project] -name = "ansible-distribution" -version = "1.0.0" +name = "ansible-dist" +version = "$VERSION" description = "Self-contained Ansible distribution" -readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=$PYTHON_VERSION" dependencies = [ "ansible>=10.0.0", "ansible-lint", "jmespath", "netaddr", - "dnspython>=2.8.0", ] [dependency-groups] -dev = [ - "pytest", -] +dev = ["pytest"] [[tool.uv.index]] name = "pypi" url = "https://nexus.it.census.gov:8443/repository/DataScience-Group/simple" EOF -# 4. Create the venv and install dependencies -# Use --python to specify 3.12, 3.13, etc. -uv venv --python "$PYTHON_VERSION" \ - --link-mode copy \ - --seed +# 4. Create the Venv with Hard Copies +uv venv .venv --python "$PYTHON_VERSION" --seed --link-mode copy +# 5. Sync dependencies source .venv/bin/activate - -# 5. Sync the environment uv sync --link-mode copy -# 6. Ensure the Python binary itself is a physical copy -# This severs the link to ~/.local/share/uv/python/... +# 6. Physical Python Binary Copy REAL_PYTHON=$(readlink -f .venv/bin/python) if [ -L ".venv/bin/python" ]; then - echo "Converting Python symlink to physical binary..." rm .venv/bin/python cp "$REAL_PYTHON" .venv/bin/python fi -# 7. Optional: Make Relocatable +# 7. Optional: Relocatable Shebangs if [ "$MAKE_RELOCATABLE" -eq 1 ]; then - echo "MAKE_RELOCATABLE is active. Patching shebangs..." - # Replaces absolute path shebangs with /usr/bin/env python - # This allows the binaries to work regardless of the parent directory path find .venv/bin -maxdepth 1 -type f -executable -exec \ sed -i '1s|#!.*python|#!/usr/bin/env python|' {} + -else - echo "Skipping relocation patch. Scripts will use absolute paths: $APP_DIR" fi -# 8. Link bin to .venv/bin for easy access to all tools +# 8. Link bin ln -snf .venv/bin bin -echo "------------------------------------------------" -echo "Ansible distribution ready at $APP_DIR" -echo "Relocatable: $([ "$MAKE_RELOCATABLE" -eq 1 ] && echo "YES" || echo "NO")" -echo "Try: $APP_DIR/bin/ansible --version" -echo "------------------------------------------------" +# 9. Create /etc/profile.d script +cat < ansible_path.sh +# Ansible Distribution Path Configuration +# Copy this to /etc/profile.d/ansible.sh +if [ -d "$APP_DIR/bin" ]; then + export PATH="$APP_DIR/bin:\$PATH" +fi +EOF + +echo "Setup complete. Version $VERSION created."