Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion stackbox/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""StackBox CLI entry point - class-based architecture."""

from pathlib import Path
import shutil
import subprocess
import sys
import time

Expand Down Expand Up @@ -511,14 +513,45 @@ def init(
click.echo(f"\n❌ Failed to generate Tempest configuration: {e}", err=True)
sys.exit(1)

# TODO: Phase 10 (Issue #12): Install Tempest and ironic-tempest-plugin
# Phase 10: Build Tempest container
click.echo("\n🐳 Building Tempest container...")
try:
# Copy Dockerfile to config directory
tempest_dockerfile_src = (
Path(__file__).parent.parent / "templates" / "tempest" / "Dockerfile"
)
tempest_dockerfile_dest = config_dir_path / "config" / "tempest" / "Dockerfile"

shutil.copy2(tempest_dockerfile_src, tempest_dockerfile_dest)
click.echo(f" ✅ Copied: {tempest_dockerfile_dest.relative_to(Path.cwd())}")

# Build Tempest image
click.echo(" 🔨 Building Tempest image (this may take a few minutes)...")

result = subprocess.run(
["docker-compose", "build", "tempest"],
cwd=config_dir_path,
capture_output=True,
text=True,
)

if result.returncode != 0:
raise RuntimeError(f"Docker build failed: {result.stderr}")

click.echo(" ✅ Tempest image built successfully")

except Exception as e:
click.echo(f"\n❌ Failed to build Tempest container: {e}", err=True)
sys.exit(1)

click.echo("\n✅ Initialization complete!")
click.echo(" Ironic API: http://localhost:6385")
click.echo(f" Virtual node: {node_name}")
click.echo(" BMC endpoint: http://localhost:8000/redfish/v1/")
click.echo(f" Enrolled in Ironic: {enrolled_node['uuid']}")
click.echo(f" Tempest config: {tempest_conf.relative_to(Path.cwd())}")
click.echo("\n💡 Ready to run tests:")
click.echo(" sb test # Run all Tempest tests")

def rebuild(self, service: str, no_cache: bool) -> None:
"""Rebuild a service after code changes."""
Expand Down
21 changes: 21 additions & 0 deletions stackbox/templates/docker-compose.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,25 @@ services:
start_period: 30s
restart: unless-stopped

# Tempest test runner - only started on demand via profiles
tempest:
build:
context: .
dockerfile: ./config/tempest/Dockerfile
container_name: stackbox-tempest
profiles:
- testing
volumes:
- ./config/tempest:/etc/tempest:ro
- tempest-results:/tmp/tempest-results
depends_on:
ironic-api:
condition: service_healthy
networks:
- stackbox
environment:
- TEMPEST_CONFIG_DIR=/etc/tempest

volumes:
mariadb-data:
name: stackbox-mariadb-data
Expand All @@ -152,6 +171,8 @@ volumes:
name: stackbox-ironic-lib
ironic-log:
name: stackbox-ironic-log
tempest-results:
name: stackbox-tempest-results

networks:
stackbox:
Expand Down
46 changes: 46 additions & 0 deletions stackbox/templates/tempest/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Tempest container for testing Ironic
FROM ubuntu:22.04

# Prevent interactive prompts during apt install
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1

# Install system dependencies
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
python3-dev \
git \
gcc \
make \
build-essential \
libssl-dev \
libffi-dev \
curl \
&& rm -rf /var/lib/apt/lists/*

# Upgrade pip to latest version
RUN pip3 install --no-cache-dir --upgrade pip setuptools wheel

# Install Tempest framework
RUN pip3 install --no-cache-dir \
tempest

# Install ironic-tempest-plugin from git
# NOTE: Using git URL to get latest version compatible with our Ironic setup
RUN pip3 install --no-cache-dir \
git+https://opendev.org/openstack/ironic-tempest-plugin.git

# Create Tempest directories
RUN mkdir -p \
/etc/tempest \
/tmp/tempest-results

# Set working directory to Tempest config location
WORKDIR /etc/tempest

# Tempest entry point - allows flexible command invocation
ENTRYPOINT ["tempest"]

# Default command shows help
CMD ["--help"]
9 changes: 8 additions & 1 deletion tests/unit/core/test_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,21 @@ def test_libvirt_uses_containerized_uri(self, tmp_path: Path) -> None:
assert "qemu:///system" not in libvirt_uri

def test_health_checks_configured(self, tmp_path: Path) -> None:
"""Test that all services have health checks."""
"""Test that all long-running services have health checks.

Services with profiles (on-demand tools like tempest) don't need health checks.
"""
output = tmp_path / "docker-compose.yml"
generate_compose_file(output)

with output.open() as f:
data = yaml.safe_load(f)

for service_name, service in data["services"].items():
# Skip services with profiles (on-demand tools, not long-running services)
if "profiles" in service:
continue

assert "healthcheck" in service, f"{service_name} missing healthcheck"
assert "test" in service["healthcheck"]

Expand Down
Loading