Skip to content
Open
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
65 changes: 65 additions & 0 deletions appliances/nodered/3fc354db-94e0-4ced-adcb-03b1b84c89d9.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
name: Node-Red
version: 1.0.0-1
one-apps_version: 7.0.0-0
publisher: Pablo del Arco
publisher_email: [email protected]
description: |-
Node-RED is a low-code, flow-based programming tool for wiring together devices, APIs, and services. This appliance provides Node-Red
running in a Docker container on Ubuntu 22.04 LTS with VNC access and
SSH key authentication.

**Node-Red features:**
- Visual flow editor
- Integrations with devices/APIs
- Real-time data transformation
- Dashboard & UI building
- Extensible via nodes
**This appliance provides:**
- Ubuntu 22.04 LTS base operating system
- Docker Engine CE pre-installed and configured
- Node-Red container (nodered/node-red:latest) ready to run
- VNC access for desktop environment
- SSH key authentication from OpenNebula context - Web interface on port 1880
- Configurable container parameters (ports, volumes, environment variables)

**Access Methods:**
- VNC: Direct access to desktop environment
- SSH: Key-based authentication from OpenNebula - Web: Node-Red interface at http://VM_IP:1880

short_description: Node-Red with VNC access and SSH key auth
tags:
- nodered
- docker
- ubuntu
- container
- vnc
- ssh-key
format: qcow2
creation_time: 1758888057
os-id: Ubuntu
os-release: '22.04'
os-arch: x86_64
hypervisor: KVM
opennebula_version: 7.0
opennebula_template:
context:
network: 'YES'
ssh_public_key: $USER[SSH_PUBLIC_KEY]
set_hostname: $USER[SET_HOSTNAME]
cpu: '2'
disk:
image: $FILE[IMAGE_ID]
image_uname: $USER[IMAGE_UNAME]
graphics:
listen: 0.0.0.0
type: vnc
memory: '2048'
name: Node-Red
user_inputs:
oneapp_container_name: 'M|text|Container name|nodered-app|nodered-app'
oneapp_container_ports: 'M|text|Container ports (format: host:container)|1880:1880|1880:1880'
oneapp_container_env: 'O|text|Environment variables (format: VAR1=value1,VAR2=value2)||'
oneapp_container_volumes: 'O|text|Volume mounts (format: /host/path:/container/path)|/data:/data|'
inputs_order: ONEAPP_CONTAINER_NAME,ONEAPP_CONTAINER_PORTS,ONEAPP_CONTAINER_ENV,ONEAPP_CONTAINER_VOLUMES
logo: logos/nodered.png
78 changes: 78 additions & 0 deletions appliances/nodered/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Node-Red Appliance

Node-RED is a low-code, flow-based programming tool for wiring together devices, APIs, and services. This appliance provides Node-Red running in a Docker container on Ubuntu 22.04 LTS with VNC access and SSH key authentication.

## Key Features

**Node-Red capabilities:**
- Visual flow editor
- Integrations with devices/APIs
- Real-time data transformation
- Dashboard & UI building
- Extensible via nodes
**This appliance provides:**
- Ubuntu 22.04 LTS base operating system
- Docker Engine CE pre-installed and configured
- Node-Red container (nodered/node-red:latest) ready to run
- VNC access for desktop environment
- SSH key authentication from OpenNebula context
- Configurable container parameters (ports, volumes, environment variables) - Web interface on port 1880

## Quick Start

1. **Deploy the appliance** from OpenNebula marketplace
2. **Configure container settings** during VM instantiation:
- Container name: nodered-app
- Port mappings: 1880:1880
- Environment variables:
- Volume mounts: /data:/data
3. **Access the VM**:
- VNC: Direct desktop access
- SSH: `ssh root@VM_IP` (using OpenNebula context keys) - Web: Node-Red interface at http://VM_IP:1880

## Container Configuration

### Port Mappings
Format: `host_port:container_port,host_port2:container_port2`
Default: `1880:1880`

### Environment Variables
Format: `VAR1=value1,VAR2=value2`
Default: ``

### Volume Mounts
Format: `/host/path:/container/path,/host/path2:/container/path2`
Default: `/data:/data`

## Management Commands

```bash
# View running containers
docker ps

# View container logs
docker logs nodered-app

# Access container shell
docker exec -it nodered-app /bin/bash

# Restart container
systemctl restart nodered-container.service

# View container service status
systemctl status nodered-container.service
```

## Technical Details

- **Base OS**: Ubuntu 22.04 LTS
- **Container Runtime**: Docker Engine CE
- **Container Image**: nodered/node-red:latest
- **Default Ports**: 1880:1880
- **Default Volumes**: /data:/data
- **Memory Requirements**: 2GB minimum
- **Disk Requirements**: 8GB minimum

## Version History

See [CHANGELOG.md](CHANGELOG.md) for detailed version history.
234 changes: 234 additions & 0 deletions appliances/nodered/appliance.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#!/usr/bin/env bash

# Node-Red Appliance Installation Script
# Auto-generated by OpenNebula Docker Appliance Generator
# Docker Image: nodered/node-red:latest

set -o errexit -o pipefail

# List of contextualization parameters
ONE_SERVICE_PARAMS=(
'ONEAPP_CONTAINER_NAME' 'configure' 'Docker container name' 'O|text'
'ONEAPP_CONTAINER_PORTS' 'configure' 'Docker container port mappings' 'O|text'
'ONEAPP_CONTAINER_ENV' 'configure' 'Docker container environment variables' 'O|text'
'ONEAPP_CONTAINER_VOLUMES' 'configure' 'Docker container volume mappings' 'O|text'
)

# Configuration from user input
DOCKER_IMAGE="nodered/node-red:latest"
DEFAULT_CONTAINER_NAME="nodered-app"
DEFAULT_PORTS="1880:1880"
DEFAULT_ENV_VARS=""
DEFAULT_VOLUMES="/data:/data"
APP_NAME="Node-Red"
APPLIANCE_NAME="nodered"

### Appliance metadata ###############################################

# Appliance metadata
ONE_SERVICE_NAME='Node-Red'
ONE_SERVICE_VERSION='1.0' # Appliance version
ONE_SERVICE_BUILD=$(date +%s)
ONE_SERVICE_SHORT_DESCRIPTION='Node-Red Docker Container Appliance'
ONE_SERVICE_DESCRIPTION='Node-Red running in Docker container'
ONE_SERVICE_RECONFIGURABLE=true

### Appliance functions ##############################################

service_cleanup()
{
:
}

service_install()
{
export DEBIAN_FRONTEND=noninteractive

# Update system
apt-get update
apt-get upgrade -y

# Install Docker
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Enable and start Docker
systemctl enable docker
systemctl start docker

# Pre-create the data directory
mkdir -p /data
chown 1000:1000 /data

# Pull Node-RED image during installation
msg info "Pulling Node-RED Docker image"
docker pull $DOCKER_IMAGE

# Verify the image was pulled
msg info "Verifying Node-RED image was pulled:"
docker images nodered/node-red

# Configure console auto-login
systemctl stop unattended-upgrades 2>/dev/null || true
systemctl disable unattended-upgrades 2>/dev/null || true
apt-get install -y mingetty
mkdir -p /etc/systemd/system/[email protected]
cat > /etc/systemd/system/[email protected]/override.conf << 'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin root %I $TERM
Type=idle
EOF

# Configure serial console and set root password
mkdir -p /etc/systemd/system/[email protected]
cat > /etc/systemd/system/[email protected]/override.conf << 'EOF'
[Service]
ExecStart=
ExecStart=-/sbin/agetty --noissue --autologin root %I 115200,38400,9600 vt102
Type=idle
EOF
echo 'root:opennebula' | chpasswd
systemctl enable [email protected] [email protected]

# Create welcome message
cat > /etc/profile.d/99-nodered-welcome.sh << 'EOF'
#!/bin/bash
case $- in *i*) ;; *) return;; esac
echo "=================================================="
echo " Node-RED Appliance - Container: nodered-app"
echo " Commands: docker ps | docker logs nodered-app"
echo "=================================================="
EOF
chmod +x /etc/profile.d/99-nodered-welcome.sh

# Clean up
apt-get autoremove -y
apt-get autoclean
find /var/log -type f -exec truncate -s 0 {} \;

sync
}

service_configure()
{
msg info "Starting Node-RED service configuration"

# Verify Docker is running
if ! systemctl is-active --quiet docker; then
msg error "Docker service is not running"
return 1
fi

msg info "✓ Docker service is running"
return 0
}

service_bootstrap()
{
msg info "Starting Node-RED service bootstrap"

# Setup and start the Node-RED container
setup_nodered_container

return $?
}

# Setup Node-RED container
setup_nodered_container()
{
local container_name="${ONEAPP_CONTAINER_NAME:-$DEFAULT_CONTAINER_NAME}"
local container_ports="${ONEAPP_CONTAINER_PORTS:-$DEFAULT_PORTS}"
local container_env="${ONEAPP_CONTAINER_ENV:-$DEFAULT_ENV_VARS}"
local container_volumes="${ONEAPP_CONTAINER_VOLUMES:-$DEFAULT_VOLUMES}"

msg info "Setting up Node-RED container: $container_name"

# Stop and remove existing container if it exists
if docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then
msg info "Stopping existing container: $container_name"
docker stop "$container_name" 2>/dev/null || true
docker rm "$container_name" 2>/dev/null || true
fi

# Parse port mappings
local port_args=""
if [ -n "$container_ports" ]; then
IFS=',' read -ra PORT_ARRAY <<< "$container_ports"
for port in "${PORT_ARRAY[@]}"; do
port_args="$port_args -p $port"
done
fi

# Parse environment variables
local env_args=""
if [ -n "$container_env" ]; then
IFS=',' read -ra ENV_ARRAY <<< "$container_env"
for env in "${ENV_ARRAY[@]}"; do
env_args="$env_args -e $env"
done
fi

# Parse volume mounts
local volume_args=""
if [ -n "$container_volumes" ]; then
IFS=',' read -ra VOL_ARRAY <<< "$container_volumes"
for vol in "${VOL_ARRAY[@]}"; do
local host_path=$(echo "$vol" | cut -d':' -f1)
mkdir -p "$host_path"
volume_args="$volume_args -v $vol"
done
fi

# Start the container
msg info "Starting Node-RED container with:"
msg info " Ports: $container_ports"
msg info " Environment: ${container_env:-none}"
msg info " Volumes: $container_volumes"

docker run -d \
--name "$container_name" \
--restart unless-stopped \
$port_args \
$env_args \
$volume_args \
"$DOCKER_IMAGE" 2>&1 | while read line; do msg info " $line"; done

if [ $? -eq 0 ]; then
msg info "✓ Node-RED container started successfully"

# Wait for container to be healthy
local max_attempts=30
local attempt=0
while [ $attempt -lt $max_attempts ]; do
if docker ps --filter "name=$container_name" --format "{{.Status}}" | grep -q "Up"; then
msg info "✓ Node-RED container is running"
local status=$(docker ps --filter "name=$container_name" --format "{{.Status}}")
msg info " Status: $status"
return 0
fi
attempt=$((attempt + 1))
sleep 2
done

# Check if container stopped unexpectedly
if docker ps -a --filter "name=$container_name" --format "{{.Status}}" | grep -q "Exited"; then
msg error "✗ Node-RED container stopped unexpectedly"
msg info "Container logs:"
docker logs "$container_name" 2>&1 | tail -10 | while read line; do
msg info " $line"
done
return 1
fi
else
msg error "✗ Failed to start Node-RED container"
return 1
fi
}
9 changes: 9 additions & 0 deletions appliances/nodered/context.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
:tests:
'nodered':
:image_name: nodered.qcow2
:type: linux
:microenvs: ['context-kvm']
:slow: true
:enable_netcfg_common: True
:enable_netcfg_ip_methods: True
7 changes: 7 additions & 0 deletions appliances/nodered/context/context.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ETH0_METHOD='dhcp'
NETWORK='YES'
SET_HOSTNAME='NodeRED'
PASSWORD='opennebula'
ETH0_MAC='00:11:22:33:44:55'
NETCFG_TYPE='nm'
START_SCRIPT_BASE64="Z2F3ayAtaSBpbnBsYWNlIC1mLSAvZXRjL3NzaC9zc2hkX2NvbmZpZyA8PCdFT0YnCkJFR0lOIHsgdXBkYXRlID0gIlBhc3N3b3JkQXV0aGVudGljYXRpb24geWVzIiB9Ci9eWyNcc10qUGFzc3dvcmRBdXRoZW50aWNhdGlvblxzLyB7ICQwID0gdXBkYXRlOyBmb3VuZCA9IDEgfQp7IHByaW50IH0KRU5ERklMRSB7IGlmICghZm91bmQpIHByaW50IHVwZGF0ZSB9CkVPRgoKZ2F3ayAtaSBpbnBsYWNlIC1mLSAvZXRjL3NzaC9zc2hkX2NvbmZpZyA8PCdFT0YnCkJFR0lOIHsgdXBkYXRlID0gIlBlcm1pdFJvb3RMb2dpbiB5ZXMiIH0KL15bI1xzXSpQZXJtaXRSb290TG9naW5ccy8geyAkMCA9IHVwZGF0ZTsgZm91bmQgPSAxIH0KeyBwcmludCB9CkVOREZJTEUgeyBpZiAoIWZvdW5kKSBwcmludCB1cGRhdGUgfQpFT0YKCnN5c3RlbWN0bCByZWxvYWQgc3NoZAoKZWNobyAibmFtZXNlcnZlciAxLjEuMS4xIiA+IC9ldGMvcmVzb2x2LmNvbmYK"
Loading
Loading