diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile new file mode 100644 index 0000000..5348829 --- /dev/null +++ b/.github/docker/Dockerfile @@ -0,0 +1,121 @@ +# Dockerfile for Stretch Robot Installation +# Can be executed in GitHub Actions workflows or manually +# Usage: +# docker build -t stretch-install -f .github/docker/Dockerfile . +# docker run --rm stretch-install + +FROM ubuntu:22.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Set the FLEET_ID environment variable +# This will be used by the installation scripts +ARG SETUP_FLEET_ID=stretch-se3-0000 +ENV SETUP_FLEET_ID=${SETUP_FLEET_ID} +ENV USER=hello-robot + +# Install basic dependencies required by the installation scripts +# Including iputils-ping for network connectivity checks and zip for logs packaging +# Pre-install heavy Python dependencies via apt to avoid compiling them from source +RUN apt-get update && apt-get install -y \ + sudo \ + git \ + curl \ + wget \ + ca-certificates \ + gnupg \ + lsb-release \ + iputils-ping \ + expect \ + zip \ + software-properties-common \ + apt-utils \ + python3-numpy \ + python3-scipy \ + python3-yaml \ + && rm -rf /var/lib/apt/lists/* + +# Pre-create necessary directories that don't exist by default in basic Docker images +# Also mock udevadm and update-initramfs which are not useful inside Docker and fail/warn in container environments +RUN mkdir -p /etc/udev/rules.d /etc/modprobe.d /etc/apt/keyrings && \ + printf '#!/bin/sh\nexit 0\n' > /usr/sbin/update-initramfs && \ + chmod +x /usr/sbin/update-initramfs && \ + printf '#!/bin/sh\nexit 0\n' > /usr/bin/udevadm && \ + chmod +x /usr/bin/udevadm + +# Create a non-root user 'hello-robot' with sudo privileges +# The installation scripts expect to run as a regular user with sudo access +RUN useradd -m -s /bin/bash hello-robot && \ + echo "hello-robot ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Switch to the hello-robot user +USER hello-robot +WORKDIR /home/hello-robot + +# Copy the entire stretch_install repository to the container +# This must be in the home directory as expected by the scripts +COPY --chown=hello-robot:hello-robot . /home/hello-robot/stretch_install + +# Patch the stretch_initial_setup.sh script to skip git checks and network connectivity checks in Docker +# This is necessary because: +# 1. The git remote check won't work in a Docker build context (no .git directory is copied due to .dockerignore) +# 2. Network connectivity checks (pinging google.com) may fail in some Docker build environments +RUN cd /home/hello-robot/stretch_install/factory/22.04 && \ + cp stretch_initial_setup.sh stretch_initial_setup.sh.orig && \ + sed -i '/^echo "Checking install repo is up-to-date..."/,/^fi$/d' stretch_initial_setup.sh && \ + sed -i '/^echo "Waiting to get online..."/,/^done$/c\echo "Skipping network check in Docker environment..."' stretch_initial_setup.sh + +# Create the calibration data directory structure +# The installation script expects calibration data in $HOME/ +# For Docker builds, we'll create a minimal structure to satisfy the script +RUN mkdir -p /home/hello-robot/${SETUP_FLEET_ID}/udev && \ + echo '# Minimal udev rules for Docker build' > /home/hello-robot/${SETUP_FLEET_ID}/udev/stretch-device.rules && \ + printf 'robot:\n batch_name: NA\n serial_no: "%s"\n model_name: SE3\n tool: eoa_wrist_dw3_tool_sg3\n' "${SETUP_FLEET_ID##*-}" > /home/hello-robot/${SETUP_FLEET_ID}/stretch_configuration_params.yaml && \ + touch /home/hello-robot/${SETUP_FLEET_ID}/stretch_user_params.yaml && \ + chmod -R a+r /home/hello-robot/${SETUP_FLEET_ID} + +# Pre-create required directories to ensure proper permissions +RUN mkdir -p /home/hello-robot/stretch_user/log && \ + mkdir -p /home/hello-robot/stretch_user/debug && \ + mkdir -p /home/hello-robot/stretch_user/maps && \ + mkdir -p /home/hello-robot/stretch_user/models && \ + mkdir -p /home/hello-robot/.local/bin + +# Set up error handling for the installation +# The script already uses 'set -e' and 'set -o pipefail' for error propagation +# We'll use shell options to ensure any errors cause the build to fail +SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] + +# Run the installation script with the FLEET_ID environment variable +# The -H flag passes the complete fleet ID to the script +# We redirect stderr to stdout to capture all output +# The script will exit with non-zero code on failure, causing the build to fail +RUN cd /home/hello-robot/stretch_install && \ + bash -c 'yes | ./stretch_new_robot_install.sh -H ${SETUP_FLEET_ID} 2>&1 | tee /home/hello-robot/stretch_user/log/docker_install.log; exit ${PIPESTATUS[1]}' + +# Verify that the FLEET_ID was properly configured in both locations +RUN if [ ! -f /etc/hello-robot/hello-robot.conf ]; then \ + echo "ERROR: /etc/hello-robot/hello-robot.conf not found"; \ + exit 1; \ + fi && \ + if ! grep -q "HELLO_FLEET_ID=${SETUP_FLEET_ID}" /etc/hello-robot/hello-robot.conf; then \ + echo "ERROR: FLEET_ID not properly configured in /etc/hello-robot/hello-robot.conf"; \ + cat /etc/hello-robot/hello-robot.conf; \ + exit 1; \ + fi && \ + if [ ! -d /home/hello-robot/stretch_user/${SETUP_FLEET_ID} ]; then \ + echo "ERROR: /home/hello-robot/stretch_user/${SETUP_FLEET_ID} directory not found"; \ + exit 1; \ + fi && \ + echo "SUCCESS: FLEET_ID properly configured in all required locations" + +# Set the default command to display installation success and fleet ID +CMD ["/bin/bash", "-c", "echo 'Stretch Robot Installation Complete' && \ + echo 'Fleet ID: '${SETUP_FLEET_ID} && \ + echo 'Configuration verified in:' && \ + echo ' - /etc/hello-robot/hello-robot.conf' && \ + echo ' - /home/hello-robot/stretch_user/'${SETUP_FLEET_ID} && \ + /bin/bash"] + diff --git a/.github/docker/Dockerfile.18.04 b/.github/docker/Dockerfile.18.04 new file mode 100644 index 0000000..b615525 --- /dev/null +++ b/.github/docker/Dockerfile.18.04 @@ -0,0 +1,123 @@ +# Dockerfile for Stretch Robot Installation (Ubuntu 18.04 - RE1) +# Can be executed in GitHub Actions workflows or manually +# Usage: +# docker build -t stretch-install-18.04 -f .github/docker/Dockerfile.18.04 . +# docker run --rm stretch-install-18.04 + +FROM ubuntu:18.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Set the FLEET_ID environment variable +# This will be used by the installation scripts +ARG SETUP_FLEET_ID=stretch-re1-0000 +ENV SETUP_FLEET_ID=${SETUP_FLEET_ID} +ENV USER=hello-robot + +# Install basic dependencies required by the installation scripts +# Including iputils-ping for network connectivity checks and zip for logs packaging +# Pre-install heavy Python dependencies via apt to avoid compiling them from source +RUN apt-get update && apt-get install -y \ + sudo \ + git \ + curl \ + wget \ + ca-certificates \ + gnupg \ + lsb-release \ + iputils-ping \ + expect \ + zip \ + software-properties-common \ + apt-utils \ + python-numpy \ + python-scipy \ + python-yaml \ + python3-numpy \ + python3-scipy \ + python3-yaml \ + && rm -rf /var/lib/apt/lists/* + +# Pre-create necessary directories that don't exist by default in basic Docker images +# Also mock udevadm and update-initramfs which are not useful inside Docker and fail/warn in container environments +RUN mkdir -p /etc/udev/rules.d /etc/modprobe.d /etc/apt/keyrings && \ + printf '#!/bin/sh\nexit 0\n' > /usr/sbin/update-initramfs && \ + chmod +x /usr/sbin/update-initramfs && \ + printf '#!/bin/sh\nexit 0\n' > /usr/bin/udevadm && \ + chmod +x /usr/bin/udevadm + +# Create a non-root user 'hello-robot' with sudo privileges +# The installation scripts expect to run as a regular user with sudo access +RUN useradd -m -s /bin/bash hello-robot && \ + echo "hello-robot ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Switch to the hello-robot user +USER hello-robot +WORKDIR /home/hello-robot + +# Copy the entire stretch_install repository to the container +# This must be in the home directory as expected by the scripts +COPY --chown=hello-robot:hello-robot . /home/hello-robot/stretch_install + +# Patch the stretch_initial_setup.sh script to skip git checks and network connectivity checks in Docker +# This is necessary because: +# 1. The git remote check won't work in a Docker build context (no .git directory is copied due to .dockerignore) +# 2. Network connectivity checks (pinging google.com) may fail in some Docker build environments +RUN cd /home/hello-robot/stretch_install/factory/18.04 && \ + cp stretch_initial_setup.sh stretch_initial_setup.sh.orig && \ + sed -i '/^echo "Checking install repo is up-to-date..."/,/^fi$/d' stretch_initial_setup.sh && \ + sed -i '/^echo "Waiting to get online..."/,/^done$/c\echo "Skipping network check in Docker environment..."' stretch_initial_setup.sh + +# Create the calibration data directory structure +# The installation script expects calibration data in $HOME/ +# For Docker builds, we'll create a minimal structure to satisfy the script +RUN mkdir -p /home/hello-robot/${SETUP_FLEET_ID}/udev && \ + echo '# Minimal udev rules for Docker build' > /home/hello-robot/${SETUP_FLEET_ID}/udev/stretch-device.rules && \ + printf 'robot:\n batch_name: NA\n serial_no: "%s"\n model_name: RE1\n tool: eoa_wrist_dw3_tool_sg3\n' "${SETUP_FLEET_ID##*-}" > /home/hello-robot/${SETUP_FLEET_ID}/stretch_configuration_params.yaml && \ + touch /home/hello-robot/${SETUP_FLEET_ID}/stretch_user_params.yaml && \ + chmod -R a+r /home/hello-robot/${SETUP_FLEET_ID} + +# Pre-create required directories to ensure proper permissions +RUN mkdir -p /home/hello-robot/stretch_user/log && \ + mkdir -p /home/hello-robot/stretch_user/debug && \ + mkdir -p /home/hello-robot/stretch_user/maps && \ + mkdir -p /home/hello-robot/stretch_user/models && \ + mkdir -p /home/hello-robot/.local/bin + +# Set up error handling for the installation +# The script already uses 'set -e' and 'set -o pipefail' for error propagation +# We'll use shell options to ensure any errors cause the build to fail +SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] + +# Run the installation script with the FLEET_ID environment variable +# The -H flag passes the complete fleet ID to the script +# We redirect stderr to stdout to capture all output +# The script will exit with non-zero code on failure, causing the build to fail +RUN cd /home/hello-robot/stretch_install && \ + bash -c 'yes | ./stretch_new_robot_install.sh -H ${SETUP_FLEET_ID} 2>&1 | tee /home/hello-robot/stretch_user/log/docker_install.log; exit ${PIPESTATUS[1]}' + +# Verify that the FLEET_ID was properly configured in both locations +RUN if [ ! -f /etc/hello-robot/hello-robot.conf ]; then \ + echo "ERROR: /etc/hello-robot/hello-robot.conf not found"; \ + exit 1; \ + fi && \ + if ! grep -q "HELLO_FLEET_ID=${SETUP_FLEET_ID}" /etc/hello-robot/hello-robot.conf; then \ + echo "ERROR: FLEET_ID not properly configured in /etc/hello-robot/hello-robot.conf"; \ + cat /etc/hello-robot/hello-robot.conf; \ + exit 1; \ + fi && \ + if [ ! -d /home/hello-robot/stretch_user/${SETUP_FLEET_ID} ]; then \ + echo "ERROR: /home/hello-robot/stretch_user/${SETUP_FLEET_ID} directory not found"; \ + exit 1; \ + fi && \ + echo "SUCCESS: FLEET_ID properly configured in all required locations" + +# Set the default command to display installation success and fleet ID +CMD ["/bin/bash", "-c", "echo 'Stretch Robot Installation Complete' && \ + echo 'Fleet ID: '${SETUP_FLEET_ID} && \ + echo 'Configuration verified in:' && \ + echo ' - /etc/hello-robot/hello-robot.conf' && \ + echo ' - /home/hello-robot/stretch_user/'${SETUP_FLEET_ID} && \ + /bin/bash"] diff --git a/.github/docker/Dockerfile.20.04 b/.github/docker/Dockerfile.20.04 new file mode 100644 index 0000000..fed2c32 --- /dev/null +++ b/.github/docker/Dockerfile.20.04 @@ -0,0 +1,120 @@ +# Dockerfile for Stretch Robot Installation (Ubuntu 20.04 - RE2) +# Can be executed in GitHub Actions workflows or manually +# Usage: +# docker build -t stretch-install-20.04 -f .github/docker/Dockerfile.20.04 . +# docker run --rm stretch-install-20.04 + +FROM ubuntu:20.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive +ENV TZ=UTC + +# Set the FLEET_ID environment variable +# This will be used by the installation scripts +ARG SETUP_FLEET_ID=stretch-re2-0000 +ENV SETUP_FLEET_ID=${SETUP_FLEET_ID} +ENV USER=hello-robot + +# Install basic dependencies required by the installation scripts +# Including iputils-ping for network connectivity checks and zip for logs packaging +# Pre-install heavy Python dependencies via apt to avoid compiling them from source +RUN apt-get update && apt-get install -y \ + sudo \ + git \ + curl \ + wget \ + ca-certificates \ + gnupg \ + lsb-release \ + iputils-ping \ + expect \ + zip \ + software-properties-common \ + apt-utils \ + python3-numpy \ + python3-scipy \ + python3-yaml \ + && rm -rf /var/lib/apt/lists/* + +# Pre-create necessary directories that don't exist by default in basic Docker images +# Also mock udevadm and update-initramfs which are not useful inside Docker and fail/warn in container environments +RUN mkdir -p /etc/udev/rules.d /etc/modprobe.d /etc/apt/keyrings && \ + printf '#!/bin/sh\nexit 0\n' > /usr/sbin/update-initramfs && \ + chmod +x /usr/sbin/update-initramfs && \ + printf '#!/bin/sh\nexit 0\n' > /usr/bin/udevadm && \ + chmod +x /usr/bin/udevadm + +# Create a non-root user 'hello-robot' with sudo privileges +# The installation scripts expect to run as a regular user with sudo access +RUN useradd -m -s /bin/bash hello-robot && \ + echo "hello-robot ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Switch to the hello-robot user +USER hello-robot +WORKDIR /home/hello-robot + +# Copy the entire stretch_install repository to the container +# This must be in the home directory as expected by the scripts +COPY --chown=hello-robot:hello-robot . /home/hello-robot/stretch_install + +# Patch the stretch_initial_setup.sh script to skip git checks and network connectivity checks in Docker +# This is necessary because: +# 1. The git remote check won't work in a Docker build context (no .git directory is copied due to .dockerignore) +# 2. Network connectivity checks (pinging google.com) may fail in some Docker build environments +RUN cd /home/hello-robot/stretch_install/factory/20.04 && \ + cp stretch_initial_setup.sh stretch_initial_setup.sh.orig && \ + sed -i '/^echo "Checking install repo is up-to-date..."/,/^fi$/d' stretch_initial_setup.sh && \ + sed -i '/^echo "Waiting to get online..."/,/^done$/c\echo "Skipping network check in Docker environment..."' stretch_initial_setup.sh + +# Create the calibration data directory structure +# The installation script expects calibration data in $HOME/ +# For Docker builds, we'll create a minimal structure to satisfy the script +RUN mkdir -p /home/hello-robot/${SETUP_FLEET_ID}/udev && \ + echo '# Minimal udev rules for Docker build' > /home/hello-robot/${SETUP_FLEET_ID}/udev/stretch-device.rules && \ + printf 'robot:\n batch_name: NA\n serial_no: "%s"\n model_name: RE2\n tool: eoa_wrist_dw3_tool_sg3\n' "${SETUP_FLEET_ID##*-}" > /home/hello-robot/${SETUP_FLEET_ID}/stretch_configuration_params.yaml && \ + touch /home/hello-robot/${SETUP_FLEET_ID}/stretch_user_params.yaml && \ + chmod -R a+r /home/hello-robot/${SETUP_FLEET_ID} + +# Pre-create required directories to ensure proper permissions +RUN mkdir -p /home/hello-robot/stretch_user/log && \ + mkdir -p /home/hello-robot/stretch_user/debug && \ + mkdir -p /home/hello-robot/stretch_user/maps && \ + mkdir -p /home/hello-robot/stretch_user/models && \ + mkdir -p /home/hello-robot/.local/bin + +# Set up error handling for the installation +# The script already uses 'set -e' and 'set -o pipefail' for error propagation +# We'll use shell options to ensure any errors cause the build to fail +SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] + +# Run the installation script with the FLEET_ID environment variable +# The -H flag passes the complete fleet ID to the script +# We redirect stderr to stdout to capture all output +# The script will exit with non-zero code on failure, causing the build to fail +RUN cd /home/hello-robot/stretch_install && \ + bash -c 'yes | ./stretch_new_robot_install.sh -H ${SETUP_FLEET_ID} 2>&1 | tee /home/hello-robot/stretch_user/log/docker_install.log; exit ${PIPESTATUS[1]}' + +# Verify that the FLEET_ID was properly configured in both locations +RUN if [ ! -f /etc/hello-robot/hello-robot.conf ]; then \ + echo "ERROR: /etc/hello-robot/hello-robot.conf not found"; \ + exit 1; \ + fi && \ + if ! grep -q "HELLO_FLEET_ID=${SETUP_FLEET_ID}" /etc/hello-robot/hello-robot.conf; then \ + echo "ERROR: FLEET_ID not properly configured in /etc/hello-robot/hello-robot.conf"; \ + cat /etc/hello-robot/hello-robot.conf; \ + exit 1; \ + fi && \ + if [ ! -d /home/hello-robot/stretch_user/${SETUP_FLEET_ID} ]; then \ + echo "ERROR: /home/hello-robot/stretch_user/${SETUP_FLEET_ID} directory not found"; \ + exit 1; \ + fi && \ + echo "SUCCESS: FLEET_ID properly configured in all required locations" + +# Set the default command to display installation success and fleet ID +CMD ["/bin/bash", "-c", "echo 'Stretch Robot Installation Complete' && \ + echo 'Fleet ID: '${SETUP_FLEET_ID} && \ + echo 'Configuration verified in:' && \ + echo ' - /etc/hello-robot/hello-robot.conf' && \ + echo ' - /home/hello-robot/stretch_user/'${SETUP_FLEET_ID} && \ + /bin/bash"] diff --git a/.github/docker/README.md b/.github/docker/README.md new file mode 100644 index 0000000..27bc327 --- /dev/null +++ b/.github/docker/README.md @@ -0,0 +1,60 @@ +# Docker-Based Stretch Installation Testing + +This directory contains utility scripts and configurations for building and testing the Stretch Robot Installation script (`stretch_new_robot_install.sh`) in an isolated Docker container. + +A GitHub Actions workflow is also configured to run these tests automatically on push or pull requests to the `master` branch. + +--- + +## 1. Running Tests Locally + +You can run the build and verification steps locally on any system with Docker installed. + +### Step A: Build the Docker Image +The `build.sh` script handles building the Docker image. It accepts a specific robot Fleet ID to mock the calibration and configuration files. + +To build the default image (`stretch-install:stretch-se3-0000`): +```bash +./.github/docker/build.sh +``` + +To build for a specific model (e.g., `stretch-re2-0001`): +```bash +./.github/docker/build.sh -f stretch-re2-0001 +``` + +To build with a custom image name: +```bash +./.github/docker/build.sh -f stretch-re2-0001 -n custom-stretch-test +``` + +### Step B: Run the Verification Tests +The `test.sh` script runs a suite of 12 verification checks (e.g., checking configuration files, installed packages, ROS Humble installation, directory structures, and log status) against the built image. + +To test the default image: +```bash +./.github/docker/test.sh -i stretch-install:stretch-se3-0000 +``` + +To test a custom-named image: +```bash +./.github/docker/test.sh -i custom-stretch-test:stretch-re2-0001 +``` + +--- + +## 2. Shared Utilities (`common.sh`) +Both scripts source [common.sh](./common.sh) for shared configurations: +* **Color Definitions & Log Handlers**: Provides unified log output styling (`[INFO]`, `[PASS]`, `[FAIL]`, etc.). +* **Docker Check**: Detects if your user is in the `docker` group and automatically prepends `sudo` to docker commands if root permissions are required. + +--- + +## 3. Automated GitHub Actions Workflow +The workflow file at [test-installation.yaml](../workflows/test-installation.yaml) runs these same scripts automatically in GitHub Actions for every pull request and push to `master`. + +It uses a matrix strategy to test multiple models (e.g., `stretch-se3-0000` and `stretch-re2-0001`) concurrently: +1. Checks out the repository. +2. Sets up Docker Buildx. +3. Invokes `build.sh` to compile the Docker image. +4. Invokes `test.sh` to run the verification tests. diff --git a/.github/docker/build.sh b/.github/docker/build.sh new file mode 100755 index 0000000..46fdc23 --- /dev/null +++ b/.github/docker/build.sh @@ -0,0 +1,118 @@ +#!/bin/bash +# Build script for Stretch Robot Installation Docker image +# This script can be used to build and test the Docker image locally + +set -e + +# Default values +FLEET_ID="${FLEET_ID:-stretch-se3-0000}" +IMAGE_NAME="${IMAGE_NAME:-stretch-install}" +DOCKERFILE_PATH=".github/docker/Dockerfile" +BUILD_CONTEXT="." + +# Source common utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [ -f "$SCRIPT_DIR/common.sh" ]; then + source "$SCRIPT_DIR/common.sh" +else + echo "Error: common.sh not found in $SCRIPT_DIR" + exit 1 +fi + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -f|--fleet-id) + FLEET_ID="$2" + shift 2 + ;; + -n|--name) + IMAGE_NAME="$2" + shift 2 + ;; + -h|--help) + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " -f, --fleet-id ID Set the fleet ID (default: stretch-se3-0000)" + echo " -n, --name NAME Set the image name (default: stretch-install)" + echo " -h, --help Display this help message" + echo "" + echo "Environment Variables:" + echo " FLEET_ID Set the fleet ID (overridden by -f flag)" + echo " IMAGE_NAME Set the image name (overridden by -n flag)" + echo "" + echo "Examples:" + echo " $0" + echo " $0 -f stretch-re2-1234" + echo " $0 -f stretch-se3-0001 -n my-stretch-install" + echo " FLEET_ID=stretch-re2-5678 $0" + exit 0 + ;; + *) + print_error "Unknown option: $1" + echo "Run '$0 --help' for usage information" + exit 1 + ;; + esac +done + +# Validate fleet ID format +if [[ ! $FLEET_ID =~ ^stretch-(re1|re2|se3)-[0-9]{4}$ ]]; then + print_error "Invalid fleet ID format: $FLEET_ID" + echo "Fleet ID must match the format: stretch-(re1|re2|se3)-XXXX" + echo "where XXXX is a 4-digit number" + exit 1 +fi + +# Determine Dockerfile based on FLEET_ID +if [[ $FLEET_ID =~ ^stretch-re1-[0-9]{4}$ ]]; then + DOCKERFILE_PATH=".github/docker/Dockerfile.18.04" +elif [[ $FLEET_ID =~ ^stretch-re2-[0-9]{4}$ ]]; then + DOCKERFILE_PATH=".github/docker/Dockerfile.20.04" +else + DOCKERFILE_PATH=".github/docker/Dockerfile" +fi + +print_info "Building Stretch Robot Installation Docker image" +print_info "Fleet ID: $FLEET_ID" +print_info "Image name: $IMAGE_NAME" +print_info "Dockerfile: $DOCKERFILE_PATH" +echo "" + +# Check if we're in the right directory +if [ ! -f "$DOCKERFILE_PATH" ]; then + print_error "Dockerfile not found at $DOCKERFILE_PATH" + print_error "Please run this script from the repository root directory" + exit 1 +fi + +# Determine if we need to use sudo for docker +detect_docker + +# Build the Docker image +print_info "Starting Docker build..." +if $DOCKER_CMD build \ + --build-arg SETUP_FLEET_ID="$FLEET_ID" \ + -t "$IMAGE_NAME:$FLEET_ID" \ + -t "$IMAGE_NAME:latest" \ + -f "$DOCKERFILE_PATH" \ + "$BUILD_CONTEXT"; then + + print_info "Docker build completed successfully!" + echo "" + print_info "Image tags:" + echo " - $IMAGE_NAME:$FLEET_ID" + echo " - $IMAGE_NAME:latest" + echo "" + print_info "To run the container:" + echo " docker run -it --rm $IMAGE_NAME:latest" + echo "" + print_info "To verify the installation:" + echo " docker run --rm $IMAGE_NAME:latest cat /etc/hello-robot/hello-robot.conf" + echo "" +else + print_error "Docker build failed!" + exit 1 +fi + diff --git a/.github/docker/common.sh b/.github/docker/common.sh new file mode 100755 index 0000000..9258148 --- /dev/null +++ b/.github/docker/common.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Common utilities for Stretch Robot Docker build and test scripts + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[PASS]${NC} $1" +} + +print_failure() { + echo -e "${RED}[FAIL]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Unified Docker command/privilege detection +DOCKER_CMD="" +detect_docker() { + if [ -n "$DOCKER_CMD" ]; then + return 0 + fi + + DOCKER_CMD="docker" + if ! docker ps >/dev/null 2>&1; then + # Try with sudo + print_warning "Docker requires elevated privileges. Checking with sudo..." + if sudo -n docker ps >/dev/null 2>&1; then + DOCKER_CMD="sudo docker" + print_warning "Using sudo for Docker commands (user not in docker group)" + else + # Need password for sudo + print_warning "Please enter your password for sudo access to Docker" + if sudo docker ps >/dev/null 2>&1; then + DOCKER_CMD="sudo docker" + print_warning "Using sudo for Docker commands (user not in docker group)" + else + print_error "Docker is not running or not accessible" + exit 1 + fi + fi + fi +} diff --git a/.github/docker/test.sh b/.github/docker/test.sh new file mode 100755 index 0000000..862b6e3 --- /dev/null +++ b/.github/docker/test.sh @@ -0,0 +1,136 @@ +#!/bin/bash +# Test script for Stretch Robot Installation Docker image +# This script verifies that the Docker installation completed successfully + +# Default values +IMAGE_NAME="${IMAGE_NAME:-stretch-install:latest}" + +# Source common utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [ -f "$SCRIPT_DIR/common.sh" ]; then + source "$SCRIPT_DIR/common.sh" +else + echo "Error: common.sh not found in $SCRIPT_DIR" + exit 1 +fi + +# Test counters +TESTS_PASSED=0 +TESTS_FAILED=0 + +# Function to run a test +run_test() { + local test_name="$1" + local test_command="$2" + + print_info "Running test: $test_name" + + if eval "$test_command"; then + print_success "$test_name" + ((TESTS_PASSED++)) + return 0 + else + print_failure "$test_name" + ((TESTS_FAILED++)) + return 1 + fi +} + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + -i|--image) + IMAGE_NAME="$2" + shift 2 + ;; + -h|--help) + echo "Usage: $0 [options]" + echo "" + echo "Options:" + echo " -i, --image NAME Set the image name to test (default: stretch-install:latest)" + echo " -h, --help Display this help message" + echo "" + echo "Examples:" + echo " $0" + echo " $0 -i stretch-install:stretch-se3-0000" + exit 0 + ;; + *) + print_failure "Unknown option: $1" + echo "Run '$0 --help' for usage information" + exit 1 + ;; + esac +done + +# Detect docker command +detect_docker + +print_info "Testing Stretch Robot Installation Docker image: $IMAGE_NAME" +echo "" + +# Test 1: Check if image exists +run_test "Image exists" \ + "$DOCKER_CMD image inspect $IMAGE_NAME > /dev/null 2>&1" + +# Test 2: Check if /etc/hello-robot/hello-robot.conf exists +run_test "Configuration file exists" \ + "$DOCKER_CMD run --rm $IMAGE_NAME test -f /etc/hello-robot/hello-robot.conf" + +# Test 3: Check if HELLO_FLEET_ID is set in configuration +run_test "FLEET_ID configured in /etc/hello-robot/hello-robot.conf" \ + "$DOCKER_CMD run --rm $IMAGE_NAME grep -q 'HELLO_FLEET_ID=' /etc/hello-robot/hello-robot.conf" + +# Test 4: Check if stretch_user directory exists +run_test "stretch_user directory exists" \ + "$DOCKER_CMD run --rm $IMAGE_NAME test -d /home/hello-robot/stretch_user" + +# Test 5: Check if fleet-specific directory exists in stretch_user +run_test "Fleet-specific directory exists in stretch_user" \ + "$DOCKER_CMD run --rm $IMAGE_NAME bash -c 'FLEET_ID=\$(grep HELLO_FLEET_ID /etc/hello-robot/hello-robot.conf | cut -d= -f2) && test -d /home/hello-robot/stretch_user/\$FLEET_ID'" + +# Test 6: Check if log directory exists +run_test "Log directory exists" \ + "$DOCKER_CMD run --rm $IMAGE_NAME test -d /home/hello-robot/stretch_user/log" + +# Test 7: Check if installation log was created +run_test "Installation log exists" \ + "$DOCKER_CMD run --rm $IMAGE_NAME test -f /home/hello-robot/stretch_user/log/docker_install.log" + +# Test 8: Check if Python is installed +run_test "Python3 is installed" \ + "$DOCKER_CMD run --rm $IMAGE_NAME which python3" + +# Test 9: Check if pip is installed +run_test "pip3 is installed" \ + "$DOCKER_CMD run --rm $IMAGE_NAME which pip3" + +# Test 10: Check if git is installed +run_test "git is installed" \ + "$DOCKER_CMD run --rm $IMAGE_NAME which git" + +# Test 11: Check if .bashrc was updated +run_test ".bashrc contains HELLO_FLEET_ID" \ + "$DOCKER_CMD run --rm $IMAGE_NAME grep -q 'HELLO_FLEET_ID' /home/hello-robot/.bashrc" + +# Test 12: Check if .local/bin directory exists +run_test ".local/bin directory exists" \ + "$DOCKER_CMD run --rm $IMAGE_NAME test -d /home/hello-robot/.local/bin" + +echo "" +echo "========================================" +echo "Test Summary" +echo "========================================" +echo -e "${GREEN}Passed:${NC} $TESTS_PASSED" +echo -e "${RED}Failed:${NC} $TESTS_FAILED" +echo "Total: $((TESTS_PASSED + TESTS_FAILED))" +echo "========================================" + +if [ $TESTS_FAILED -eq 0 ]; then + print_success "All tests passed!" + exit 0 +else + print_failure "Some tests failed!" + exit 1 +fi + diff --git a/.github/workflows/test_with_docker.yaml b/.github/workflows/test_with_docker.yaml new file mode 100644 index 0000000..536ae1e --- /dev/null +++ b/.github/workflows/test_with_docker.yaml @@ -0,0 +1,58 @@ +name: Run stretch_new_robot_install.sh in a Docker container + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: # Allow manual triggering + +jobs: + test-docker-installation: + runs-on: ubuntu-latest + timeout-minutes: 120 # Installation can take a while + + strategy: + matrix: + fleet_id: + - stretch-se3-0000 + - stretch-re2-0001 + - stretch-re1-0000 + fail-fast: true # If False, continue testing other fleet IDs even if one fails + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Make scripts executable + run: | + chmod +x .github/docker/build.sh + chmod +x .github/docker/test.sh + + - name: Build Docker image + run: | + ./.github/docker/build.sh -f ${{ matrix.fleet_id }} -n stretch-install-test + + - name: Verify installation + run: | + ./.github/docker/test.sh -i stretch-install-test:${{ matrix.fleet_id }} + + # - name: Extract logs from container + # if: always() + # run: | + # # Create a temporary container to extract logs + # container_id=$(docker create stretch-install-test:${{ matrix.fleet_id }}) + # docker cp $container_id:/home/hello-robot/stretch_user/log /tmp/stretch-logs-${{ matrix.fleet_id }} || true + # docker rm $container_id + + # - name: Upload extracted logs + # if: always() + # uses: actions/upload-artifact@v3 + # with: + # name: stretch-installation-logs-${{ matrix.fleet_id }} + # path: /tmp/stretch-logs-${{ matrix.fleet_id }}/ + # retention-days: 30 + # if-no-files-found: ignore