An open API service indexing awesome lists of open source software.

https://github.com/peterrichards-lr/liferay-docker-manager

A professional command-line orchestrator for quickly standing up Liferay Portal and DXP environments using Docker Compose.
https://github.com/peterrichards-lr/liferay-docker-manager

automation cli docker docker-compose dxp ldm liferay liferay-docker-manager orchestrator python sales-engineering

Last synced: 21 days ago
JSON representation

A professional command-line orchestrator for quickly standing up Liferay Portal and DXP environments using Docker Compose.

Awesome Lists containing this project

README

          

# Liferay Docker Manager (ldm)

A professional command-line orchestrator for quickly standing up Liferay Portal and DXP environments using Docker Compose.

> [!NOTE]
> **Project History:** This tool was originally born as part of the [liferay-docker-scripts](https://github.com/peterrichards-lr/liferay-docker-scripts) repository. It has since evolved into a standalone application to provide better modularity and multi-instance stability.

---

## Why use LDM?

`ldm` is designed to be both fast for power users and helpful for newcomers. It follows a consistent usage pattern:

1. **Sensible Defaults**: Whenever a standard Liferay convention exists, `ldm` uses it automatically (e.g., port `8080`, managed DB name `lportal`).
2. **Smart Context**: If you run a command from inside a project folder, `ldm` automatically detects the project context.
3. **Interactive Fallback**: If a required piece of information (like a project name or a Liferay tag) is missing from your command and cannot be detected, `ldm` will **prompt you interactively** or show you a list of choices.
4. **Graceful Abort**: You can type `q` at any interactive prompt to safely cancel the operation.

---

## 🛡️ Compatibility (Verified Environments)

The badges below represent our verified support for various Docker providers. Environments marked as **Hardened** have received specific logic refinements to handle complex file-sharing and permission scenarios.

| Architecture | Host OS | Docker Provider | Hardening | Verified |
| :--- | :--- | :--- | :--- | :--- |
| **Apple Silicon** | macOS 11+ | **OrbStack** | ![OrbStack](https://img.shields.io/badge/OrbStack-Hardened-00B0FF?style=flat-square&logo=apple) | ✅ |
| **Apple Silicon** | macOS 11+ | **Docker Desktop** | ![DockerDesktop](https://img.shields.io/badge/Docker_Desktop-Hardened-00C853?style=flat-square&logo=apple) | ✅ |
| **Apple Silicon** | macOS 11+ | **Colima** | ![Colima](https://img.shields.io/badge/Colima-Hardened-FFAB00?style=flat-square&logo=apple) | ✅ |
| **Apple Intel** | macOS 11+ | **Colima** | ![Colima](https://img.shields.io/badge/Colima-Hardened-FFAB00?style=flat-square&logo=apple) | ✅ |
| **Windows PC** | Windows 11 | **Native WSL2** | ![WSL2](https://img.shields.io/badge/WSL2-Hardened-blue?style=flat-square&logo=windows) | ✅ |
| **Windows PC** | Windows 11 | **Docker Desktop** | ![DockerDesktop](https://img.shields.io/badge/Docker_Desktop-Hardened-00C853?style=flat-square&logo=windows) | ✅ |
| **Linux Workstation** | Fedora 43 | **Native Docker** | ![Fedora](https://img.shields.io/badge/Fedora-Hardened-success?style=flat-square&logo=linux) | ✅ |
| **Linux Node** | Ubuntu 22.04 | **Docker Engine** | ![Linux](https://img.shields.io/badge/Linux-Native-success?style=flat-square&logo=linux) | ✅ |

## Global Infrastructure

| Component | Verified Versions | Notes |
| :--- | :--- | :--- |
| **Traefik** | `v3.6.1+` | Automatic API version negotiation enabled. |
| **Elasticsearch** | `8.17.0`, `7.17.24` | Dual support with version-aware project sync. |

---

## Key Features

- **Multi-Instance Session Isolation**: Run multiple demos side-by-side on the same machine without session cross-talk. `ldm` automatically manages unique session cookie names and virtual hostnames.
- **Orchestrated Search Snapshots**: Save and restore the exact state of a demonstration, including the database, files, and **Elasticsearch 8.x index state**.
- **Service-Specific Lifecycle**: Manage individual components within a project surgically. Restart or view logs for a single extension without affecting the rest of the stack.
- **Client Extension Lifecycle**: Automatically detects and builds Server-Side Client Extensions (SSCE). Subdomains are automatically generated, and traffic is routed based on `LCP.json`.
- **Zero-Config SSL**: Automated HTTPS using `mkcert` and a global Traefik proxy. Works on Docker Desktop, **Colima**, and **WSL2**.
- **Proactive License Verification**: Automatically detects Liferay XML licenses in `common/`, `deploy/`, or `osgi/modules/` folders. Warns you before boot if a DXP license is missing or expired.
- **Fail-Fast Design**: Proactive environment checking. LDM verifies Docker reachability, volume mounts, resource allocations (CPU/RAM), and **Compose functionality** before execution, providing clean, actionable error messages instead of tracebacks.
- **Architecture-Aware**: The tool detects your OS automatically to fetch the correct optimized binary during self-updates.

---

## Documentation

- [Installation Guide](installation.md)
- [Architecture Overview](LDM_ARCHITECTURE.md)
- [Test & Validation Strategy](TESTING.md)
- [Security Posture & Disclosures](SECURITY.md)
- [Future Roadmap](roadmap.md)

---

## Scripting & Automation

LDM is designed to be pipeline-friendly. The `ldm doctor` command returns a non-zero exit code if critical environment issues are detected.

### Health Check Pipe

Ensure your environment is healthy before attempting to start a project:

```bash
ldm doctor --skip-project && ldm run my-project
```

### Automation Patterns

Check if services are running before executing operations:

```bash
# Start infrastructure only if it's not already running
ldm ps || ldm infra-setup --search
```

### CI/CD Integration

You can use LDM in automated scripts to verify infrastructure:

```bash
if ldm doctor --skip-project; then
echo "Environment is healthy, proceeding..."
else
echo "Critical environment failure!"
exit 1
fi
```

---

## Installation (Quick Start)

The standalone binary is the recommended way to use LDM.

```bash
# For macOS (Apple Silicon)
sudo curl -L https://github.com/peterrichards-lr/liferay-docker-manager/releases/latest/download/ldm-macos-arm64 -o /usr/local/bin/ldm

# For macOS (Apple Intel)
sudo curl -L https://github.com/peterrichards-lr/liferay-docker-manager/releases/latest/download/ldm-macos-x86_64 -o /usr/local/bin/ldm

# For Linux / WSL2
sudo curl -L https://github.com/peterrichards-lr/liferay-docker-manager/releases/latest/download/ldm-linux -o /usr/local/bin/ldm

# Make it executable
sudo chmod +x /usr/local/bin/ldm
```

For detailed instructions and Windows setup, see the **[Full Installation Guide](installation.md)**.

---

## Quick Start

> [!IMPORTANT]
> **Binary vs Script**: If you have installed the **Standalone Binary**, use `ldm` in your commands. If you are using the **Manual Installation**, use `./ldm` (on Linux/macOS) or `ldm.bat` (on Windows) from the root of this repository.

```bash
# 1. THE CONFIDENCE BOOSTER: Run Liferay with pre-configured samples
ldm run my-sample-project --samples

# 2. THE DEVELOPER FLOW: Initialize from a workspace and start monitoring
ldm init-from /path/to/workspace my-project

# 3. THE ARCHIVE FLOW: Import a static snapshot of a workspace
ldm import /path/to/workspace my-static-project

# 4. THE RECOVERY FLOW: Re-create a deleted project from a snapshot folder
ldm run my-recovered-project --snapshot ~/Desktop/old-baseline-snapshot

# Monitor an existing project (manually)
ldm monitor /path/to/workspace
```

---

## Command Reference

### `list` (alias: `ls`)

Display a tabulated overview of all initialized LDM sandbox environments.

```bash
ldm list
ldm ls
```

### `run` (alias: `up`)

Initialize and start a project stack.

```bash
# Run with a specific tag and virtual hostname
ldm run --tag 2024.q4.0 --host-name demo.local

# Using the alias
ldm up demo

# Initialize with "Confidence Booster" samples
ldm run demo --samples

# Interactive run (will prompt for version and project name)
ldm run
```

#### SSL Defaults (New Projects)

LDM uses smarter defaults for SSL based on your hostname. When a custom `--host-name` is used, SSL is enabled by default to support modern Liferay features like Client Extensions.

| Command | Host Name | SSL Default | Access URL |
| :--- | :--- | :--- | :--- |
| `ldm run` | `localhost` | `False` | `http://localhost:8080` |
| `ldm run --host-name my.local` | `my.local` | `True` | `https://my.local` |
| `ldm run --no-ssl` | `localhost` | `False` | `http://localhost:8080` |
| `ldm run --host-name my.local --no-ssl` | `my.local` | `False` | `http://my.local:8080` |

### `init-from` (Live Link)

Initialize a project from a source workspace and establish a **persistent link**. This command records the workspace path in the project metadata and automatically starts the `monitor` process to sync your code changes in real-time.

```bash
ldm init-from ~/repos/my-workspace my-project
```

### `import` (Static Snapshot)

Scaffold a new project by taking a **one-time static import** of an existing workspace. This project is detached from the source; changes to the source workspace will not be synced. Follows the same internal deployment sequence as `init-from`.

```bash
ldm import ~/repos/my-workspace my-static-project
```

### `monitor`

Restarts the background watch process for a project linked to a Liferay workspace. This command can **only be used for projects created with `init-from`**. It automatically syncs built artifacts (`.jar`, `.war`, `.zip`) whenever they are updated in the workspace.

```bash
ldm monitor [project_name] --delay 2.0
```

### `logs`

View real-time logs. Supports filtering by project and specific service.

```bash
ldm logs [project] [service]

# Examples:
ldm logs # All logs for current project
ldm logs demo # All logs for 'demo' project
ldm logs demo liferay # Only Liferay logs for 'demo'
ldm logs demo my-extension # Only logs for a specific client extension
```

### `stop`, `restart`, `down` (alias: `rm`)

Manage the lifecycle of a project or a specific service.

```bash
ldm stop [project] [service] # Stop containers gracefully
ldm restart [project] [service] # Stop and then start
ldm down [project] [service] # Remove containers (and optionally -v volumes)
ldm rm [project] # Alias for 'down'

# Examples:
ldm restart # Full stack restart (graceful stop + run)
ldm restart demo liferay # Surgical restart of just the Liferay container
ldm down --volumes # Tear down stack and clear all database/data state
ldm rm demo -v # Remove 'demo' and its volumes
```

### `deploy`

Hot-deploy built artifacts or rebuild extension images.

```bash
ldm deploy [project] [service] --rebuild

# Examples:
ldm deploy # Sync all artifacts and refresh stack
ldm deploy demo my-ext --rebuild # Rebuild and restart one extension
```

### `scale`

Scale services within a project for multi-node simulation and clustering tests.

```bash
ldm scale [project] service=count

# Examples:
ldm scale demo liferay=2 # Scale Liferay to 2 nodes (enables clustering)
ldm scale demo my-ext=3 # Scale a client extension to 3 nodes
```

### `snapshot` & `restore`

Backup and recover project states, including files, DB, and search indices.

**Examples:**

```bash
# Create a named snapshot
ldm snapshot demo --name "post-setup-gold-standard"

# List snapshots for a project
ldm restore demo --list # Non-interactive list of all snapshots
ldm restore demo --index 1 # Restore to index 1
```

### `shell` & `gogo`

Jump into a container shell for deep inspection or connect to the OSGi Gogo console for runtime management.

**Interactive Shell Examples:**

```bash
# Enter bash in the Liferay container
ldm shell demo

# Common Shell Tasks (inside container):
# 1. View live Tomcat logs
cd tomcat/logs && tail -f catalina.out

# 2. Check injected environment variables
env | grep LIFERAY

# 3. Verify mounted OSGi configurations
ls osgi/configs
```

**Gogo Shell Examples:**

```bash
# Connect to the Gogo shell (requires --gogo-port during run)
ldm gogo demo

# Common Gogo Commands:
# 1. List all active bundles
lb

# 2. Check for unresolved dependencies
diag

# 3. List declarative services (SCR)
scr:list
```

### `env`

Manage persistent environment variables in project metadata.

```bash
ldm env [project] KEY=VALUE
ldm env [project] --remove KEY
ldm env # Interactive manager (view and edit all)
```

### `cloud-fetch` (Fetch Cloud State)

Synchronize an **existing local project** with data, logs, and configuration from Liferay Cloud (LCP). This is used for local debugging and state hydration, not for importing source code.

> [!NOTE]
> **Prerequisite:** You must have the [LCP CLI](https://customer.liferay.com/documentation/cloud/latest/en/reference/command-line-tool.html) installed and authenticated (`lcp login`).

```bash
# 1. Discover available cloud environments
ldm cloud-fetch --list-envs

# 2. Stream remote logs from UAT to your local terminal
ldm cloud-fetch [project] uat liferay --logs

# 3. Pull the latest Cloud backups (DB/Data) into your local project snapshots
ldm cloud-fetch [project] uat --download

# 4. Sync Cloud environment variables to your local project metadata
ldm cloud-fetch [project] uat --sync-env
```

### `log-level`

Manage Liferay internal logging levels (Log4j2) without restarts.

```bash
# List current custom levels
ldm log-level --list

# Set a specific category to DEBUG
ldm log-level [project] --bundle portal --category com.liferay.portal --level DEBUG

# Interactive configuration
ldm log-level
```

### `doctor`

Verify host environment health, Docker resources (CPUs/Memory), and project dependencies.

```bash
ldm doctor # Health check for current/selected project
ldm doctor --all # Batch validate every project in your workspace
```

### `status` (alias: `ps`)

Lightweight summary of all active global services and running projects.

```bash
ldm status
ldm ps
```

### `browser` (alias: `open`)

Launch the project URL in your system browser. If no project is specified, LDM will present a list of currently running projects to select from.

```bash
ldm browser [project]
ldm open [project]
```

### `upgrade`

Automatically download and install the latest version of LDM for your architecture. Includes integrity verification.

```bash
ldm upgrade # Standard upgrade to latest
ldm upgrade --repair # Re-download current version to fix integrity issues
```

### `renew-ssl`

Refresh project-specific SSL certificates immediately.

```bash
ldm renew-ssl # Interactive selector
ldm renew-ssl demo # Renew for 'demo' specifically
ldm renew-ssl --all # Renew certificates for every project
```

### `init-common`

Initialize or recreate the baseline global configuration (`common/` folder) from internal resources.

```bash
ldm init-common
```

### `infra-setup`, `infra-down`, `infra-restart`

Independently manage global infrastructure services (Traefik proxy, Search sidecar, Bridge).

```bash
ldm infra-setup # Start global services manually
ldm infra-setup --search # Also initialize the Global Search container
ldm infra-down # Stop and remove global services
ldm infra-restart # Reset all global services in one go
```

> [!TIP]
> **Sidecar Fallback**: If the Global Search (ES8) container is not running, `ldm` will automatically default to Liferay's internal **Sidecar** search. It also cleans up global ES configurations in your project to ensure the Sidecar initializes correctly.

### `migrate-search`

Migrates a project from using the internal Sidecar search to the shared **Global Search container**.

```bash
ldm migrate-search [project]
```

**What it does:**

1. Verifies the project is stopped.
2. Ensures the Global Search container is running (offers to start it).
3. Deletes internal indices (`data/elasticsearch7` or `data/elasticsearch8`).
4. Re-syncs Global ES configurations from `common/`.
5. Offers to restart the project immediately.

### `reset`

Surgically clear project data folders. This command requires the project to be stopped.

```bash
ldm reset [project] [target]
```

**Available Targets:**

- **`state`** (Default): Clears the `osgi/state` folder.
- **`search`**: Clears internal Sidecar indices.
- **`db`**: Clears the Hypersonic database (if used).
- **`global-search`**: Deletes the project's indices from the shared Global Search container.
- **`all`**: Performs all of the above.

**Examples:**

```bash
ldm reset demo state # Clear OSGi state for 'demo'
ldm reset demo search,db # Clear local search and DB
ldm reset demo all # Total project data wipe
```

### `prune`

Identify and remove orphaned resources. This command scans your Docker environment for containers and global search snapshots that no longer have a matching project folder on your disk.

```bash
ldm prune
```

**What it cleans:**

- **Orphaned Containers**: Any container with the `com.liferay.ldm.managed` label whose project folder was manually deleted.
- **Orphaned Search Snapshots**: Leftover Elasticsearch 8.x snapshots in the global vault from deleted projects.
- **Temporary Files**: Residual `.*.tmp` files left behind by interrupted sync or build operations.

### `clear-cache`

Clears the local Docker Hub tag cache. LDM caches Liferay tags for 24 hours to improve performance; use this command to force a fresh fetch from the registry.

```bash
ldm clear-cache
```

### `config`

View or set global LDM configuration settings (stored in `~/.ldmrc`).

```bash
ldm config # View all global settings
ldm config key value # Set a global preference
ldm config key --remove # Remove a preference
```

---

## Configuration Files

- **`logging.json`**: Managed via `log-level` command.
- **`common/`**: Files here (configs, XML licenses, LPKG files) are synced to all project stacks.
- **`services/`**: Place standalone `Dockerfile` directories here for orchestration.

---

## Prerequisites

- **Docker Engine**: Docker Desktop, Colima, or native WSL2.
- **Docker Compose**: **v2 (Plugin)** is mandatory. Legacy v1 standalone is not supported.
- **Resources**: Recommended **4 CPUs and 8GB RAM** allocated to Docker.
- *Note*: `ldm doctor` expects these minimums. If you allocate exactly 8GB, Docker may report ~7.7GB due to system overhead; the tool accounts for this by allowing a 7.5GB threshold.
- **Python**: 3.10+ (if not using binary)
- **mkcert**: (Optional) For automated local SSL.

### Increasing Resources in Colima

If `ldm doctor` reports insufficient resources in Colima, you can increase them with these commands:

```bash
colima stop
colima start --cpu 4 --memory 8
```

---

## Interactive Mode Tips

- **Smart Project Detection**: `ldm` prioritizes project detection in this order:
1. Positional argument (e.g., `ldm run my-project`).
2. CLI flag (e.g., `ldm run -p my-project`).
3. The current working directory (if it's an LDM project).
4. An interactive list of all discovered projects.
- **Quick Quit**: You can type `q` at any interactive prompt to safely abort the current command.
- **Bypass Prompts**: Use the `-y` or `--non-interactive` flag to skip all confirmations and use default values. This is ideal for scripts and CI/CD pipelines.
- **Tag Discovery**: When running `ldm run` without a version tag, the tool will offer to fetch the latest available tags from Docker Hub based on your release type preference (LTS, QR, etc.).

---

## 🛠️ Development & Building

If you want to contribute to LDM or test your changes locally, follow these steps.

### 1. Run from Source (Live Development)

The easiest way to develop is to install LDM in "editable" mode. This allows your changes to the `ldm_core` package to take effect immediately.

```bash
# Clone the repo
git clone https://github.com/peterrichards-lr/liferay-docker-manager.git
cd liferay-docker-manager

# Install in editable mode
pip install -e .

# Run the entry point
python3 liferay_docker.py --help
```

### 2. Building Standalone Binaries

You can build a single-file executable to test how the tool behaves as a binary.

#### **Option A: Shiv (Official CI Method)**

Used for macOS and Linux. Fast and lightweight, but requires `python3` to be present on the host.

```bash
# Build only
./scripts/package-shiv.sh

# Build and install to /usr/local/bin/ldm (requires sudo)
./scripts/package-shiv.sh --install
```

#### **Option B: PyInstaller (True Standalone)**

Bundles the Python interpreter inside the file. Works even on machines without Python installed.

```bash
# Build only
./scripts/package-pyinstaller.sh

# Build and install to /usr/local/bin/ldm (requires sudo)
./scripts/package-pyinstaller.sh --install
```

The resulting binary will be found in the `dist/` folder (for PyInstaller) or the root (for Shiv).

## License

MIT © Peter Richards