Docker runtime in progress

work in progress container manager script runtime image with autostart

frdel committed Nov 14, 2024 at 20:27 UTC 7fc17b39c52b1a1036c8242a2f3fdbdc6ff3f741
9 files changed +272 -21
docker/docker_manager_macos.sh new
+137
@@ -0,0 +1,137 @@
1 +#!/bin/bash
2 +
3 +# Constants
4 +IMAGE_NAME="agent-zero-run"
5 +DEFAULT_CONTAINER_NAME="agent-zero"
6 +BASE_PORT=50080
7 +
8 +# Global variable for container IDs
9 +container_ids=()
10 +
11 +# Function to list unique containers based on the specified image
12 +list_containers() {
13 + echo
14 + echo "Listing all containers using image '$IMAGE_NAME':"
15 + container_ids=() # Reset global array for each list update
16 + container_list=$(docker ps -a --filter "ancestor=$IMAGE_NAME" --format "{{.ID}} {{.Names}} {{.Ports}}" | sort -u -k2,2)
17 +
18 + if [ -z "$container_list" ]; then
19 + echo "No containers found for image '$IMAGE_NAME'."
20 + return 1
21 + fi
22 +
23 + index=1
24 + printed_ids=()
25 + while IFS= read -r line; do
26 + container_id=$(echo "$line" | awk '{print $1}')
27 + container_name=$(echo "$line" | awk '{print $2}')
28 + ports=$(echo "$line" | awk '{print substr($0, index($0,$3))}')
29 +
30 + # Extract the mapped port using sed
31 + mapped_port=$(echo "$ports" | sed -n 's/.*0.0.0.0:\([0-9]*\)->80.*/\1/p')
32 + container_url="http://localhost:${mapped_port}"
33 +
34 + # Check if this ID has already been printed and mapped_port is valid
35 + if [[ ! " ${printed_ids[@]} " =~ " ${container_id} " ]] && [ -n "$mapped_port" ]; then
36 + printed_ids+=("$container_id")
37 + container_ids+=("$container_id") # Store container ID in global array
38 + printf "%2d. [%s] %s - URL: %s\n" "$index" "$container_id" "$container_name" "$container_url"
39 + index=$((index + 1))
40 + fi
41 + done <<< "$container_list"
42 + return 0
43 +}
44 +
45 +
46 +
47 +# Function to select an action for an existing container
48 +manage_container() {
49 + container_id=$1
50 + while true; do
51 + echo -e "\nSelect an action for container ID: $container_id"
52 + echo "1. Restart"
53 + echo "2. Remove"
54 + echo "3. View Logs"
55 + echo "0. Back"
56 + read -p "Choose an action (0-3): " action
57 + case $action in
58 + 1)
59 + docker restart "$container_id"
60 + echo "Container restarted."
61 + ;;
62 + 2)
63 + docker rm -f "$container_id"
64 + echo "Container removed."
65 + return # Go back to the list screen after removing
66 + ;;
67 + 3)
68 + echo -e "\n--- Logs for container ID: $container_id ---"
69 + docker logs "$container_id"
70 + echo -e "\n--- End of logs ---"
71 + ;;
72 + 0)
73 + return
74 + ;;
75 + *)
76 + echo "Invalid selection. Please choose 0, 1, 2, or 3."
77 + ;;
78 + esac
79 + done
80 +}
81 +
82 +# Function to create a new container
83 +create_container() {
84 + # Generate the default container name
85 + container_count=$(docker ps -a --filter "name=$DEFAULT_CONTAINER_NAME" --format "{{.Names}}" | wc -l)
86 + default_name="$DEFAULT_CONTAINER_NAME-$(($container_count + 1))"
87 +
88 + # Prompt for the container name
89 + read -p "Enter container name or leave empty for '$default_name': " name
90 + name=${name:-"$default_name"}
91 +
92 + # Calculate default port based on the container count
93 + default_port=$((BASE_PORT + container_count + 1))
94 + read -p "Enter web port or leave empty for '$default_port': " web_port
95 + web_port=${web_port:-$default_port}
96 +
97 + # Prompt for the data folder
98 + read -p "Enter data folder or leave empty for '$(pwd)/agent-zero': " data_folder
99 + data_folder=${data_folder:-$(pwd)/agent-zero}
100 +
101 + # Run the container with the specified name, port mapping, and data folder
102 + container_id=$(docker run -d -p "$web_port:80" --name "$name" -v "$data_folder:/a0" "$IMAGE_NAME:latest")
103 + echo -e "\nContainer '$name' created with ID '$container_id', data folder '$data_folder', and web port '$web_port' mapped to port 80."
104 +}
105 +
106 +# Main program loop
107 +echo -e "\nWelcome to Agent Zero Docker Management Script.\n"
108 +while true; do
109 + list_containers
110 + if [ $? -ne 0 ]; then
111 + echo -e "\nNo containers available. Would you like to create a new one? (y/n)"
112 + read -p "> " create_new
113 + if [ "$create_new" == "y" ]; then
114 + create_container
115 + else
116 + exit 0
117 + fi
118 + else
119 + echo -e "\nChoose a container by line number, type 'n' to create a new one, or 'r' to refresh the list:"
120 + read -p "> " choice
121 +
122 + # Refresh the list if the user inputs 'r'
123 + if [ "$choice" == "r" ]; then
124 + continue
125 + fi
126 +
127 + # Match choice to the actual container list
128 + if [[ $choice =~ ^[0-9]+$ ]] && ((choice >= 1 && choice <= ${#container_ids[@]})); then
129 + selected_container_id="${container_ids[$((choice - 1))]}"
130 + manage_container "$selected_container_id"
131 + elif [ "$choice" == "n" ]; then
132 + create_container
133 + else
134 + echo "Invalid choice, please enter a valid line number, 'n' to create a new container, or 'r' to refresh the list."
135 + fi
136 + fi
137 +done
docker/run/Dockerfile
+22 -7
@@ -13,8 +13,15 @@ RUN apt-get update && apt-get install -y \
13 npm \
14 openssh-server \
15 sudo \
16 - git \
17 - && rm -rf /var/lib/apt/lists/*
16 + curl \
17 + wget \
18 + git
19 +
20 +# Cleanup package list
21 +RUN rm -rf /var/lib/apt/lists/*
22 +
23 +# Clone Agent Zero repository
24 +RUN git clone --branch development https://github.com/frdel/agent-zero.git /git/agent-zero
25
26 # Set up SSH
27 RUN mkdir /var/run/sshd && \
@@ -25,18 +32,26 @@ RUN mkdir /var/run/sshd && \
32 ENV VIRTUAL_ENV=/opt/venv
33 RUN python3 -m venv $VIRTUAL_ENV
34
28 -# Copy initial .bashrc with virtual environment activation to a temporary location
29 -COPY .bashrc /etc/skel/.bashrc
30 -
35 # Copy the script to ensure .bashrc is in the root directory
36 COPY initialize.sh /usr/local/bin/initialize.sh
37 RUN chmod +x /usr/local/bin/initialize.sh
38
39 +# Copy contents of filesystem directory to /fs
40 +COPY ./fs/ /fs
41 +
42 # Ensure the virtual environment and pip setup
43 RUN $VIRTUAL_ENV/bin/pip install --upgrade pip
44
38 -# Expose SSH port
39 -EXPOSE 22
45 +# Install additional python packages
46 +RUN $VIRTUAL_ENV/bin/pip install \
47 + ipython \
48 + requests
49 +
50 +# Install A0 python packages
51 +RUN $VIRTUAL_ENV/bin/pip install -r /git/agent-zero/requirements.txt
52 +
53 +# Expose ports
54 +EXPOSE 22 80
55
56 # Init .bashrc
57 CMD ["/usr/local/bin/initialize.sh"]
\ No newline at end of file
docker/run/build.txt
+5
@@ -1 +1,6 @@
1 +# local image
2 +docker build -t agent-zero-run:latest .
3 +
4 +# dockerhub
5 +docker login
6 docker buildx build --platform linux/amd64,linux/arm64 -t frdel/agent-zero-exe:latest --push .
\ No newline at end of file
docker/run/fs/exe/node_eval.js new
+41
@@ -0,0 +1,41 @@
1 +#!/usr/bin/env node
2 +
3 +const vm = require('vm');
4 +const path = require('path');
5 +
6 +// Create a comprehensive context with all important global objects
7 +const context = vm.createContext({
8 + ...global,
9 + require: require,
10 + __filename: path.join(process.cwd(), 'eval.js'),
11 + __dirname: process.cwd(),
12 + module: { exports: {} },
13 + exports: module.exports,
14 + console: console,
15 + process: process,
16 + Buffer: Buffer,
17 + setTimeout: setTimeout,
18 + setInterval: setInterval,
19 + setImmediate: setImmediate,
20 + clearTimeout: clearTimeout,
21 + clearInterval: clearInterval,
22 + clearImmediate: clearImmediate
23 +});
24 +
25 +const code = process.argv[2];
26 +const wrappedCode = `
27 + (async function() {
28 + try {
29 + const __result__ = await eval(${JSON.stringify(code)});
30 + if (__result__ !== undefined) console.log('Out[1]:', __result__);
31 + } catch (error) {
32 + console.error(error);
33 + }
34 + })();
35 +`;
36 +
37 +vm.runInContext(wrappedCode, context, {
38 + filename: 'eval.js',
39 + lineOffset: -2,
40 + columnOffset: 0,
41 +}).catch(console.error);
\ No newline at end of file
docker/run/fs/exe/run_A0.sh new
+40
@@ -0,0 +1,40 @@
1 +#!/bin/bash
2 +
3 +# Paths
4 +PYTHON_SCRIPT="/a0/run_ui.py"
5 +SOURCE_DIR="/git/agent-zero"
6 +TARGET_DIR="/a0"
7 +
8 +
9 +# Loop to restart the Python script when it finishes
10 +while true; do
11 +
12 + # Create virtual environment if it doesn't exist
13 + if [ ! -d /opt/venv ]; then
14 + echo "Creating virtual environment..."
15 + python3 -m venv /opt/venv
16 + /opt/venv/bin/pip install ipython requests
17 + fi
18 +
19 + # Activate the virtual environment
20 + source /opt/venv/bin/activate
21 +
22 + # Copy repository files if target is empty
23 + if [ -z "$(ls -A "$TARGET_DIR")" ]; then
24 + echo "Copying files from $SOURCE_DIR to $TARGET_DIR..."
25 + cp -rn --no-preserve=ownership,mode "$SOURCE_DIR/" "$TARGET_DIR"
26 + fi
27 +
28 + echo "Starting A0..."
29 + python "$PYTHON_SCRIPT" --port 80
30 +
31 + # Check the exit status
32 + if [ $? -ne 0 ]; then
33 + echo "A0 script exited with an error. Restarting..."
34 + else
35 + echo "A0 script finished. Restarting..."
36 + fi
37 +
38 + # Optional: Add a small delay if needed to avoid rapid restarts
39 + sleep 1
40 +done
docker/run/fs/root/.bashrc renamed
docker/run/fs/root/.profile new
+9
@@ -0,0 +1,9 @@
1 +# .bashrc
2 +
3 +# Source global definitions
4 +if [ -f /etc/bashrc ]; then
5 + . /etc/bashrc
6 +fi
7 +
8 +# Activate the virtual environment
9 +source /opt/venv/bin/activate
docker/run/initialize.sh
+10 -11
@@ -1,18 +1,17 @@
1 #!/bin/bash
2
3 -# Ensure .bashrc is in the root directory
4 -if [ ! -f /root/.bashrc ]; then
5 - cp /etc/skel/.bashrc /root/.bashrc
6 - chmod 444 /root/.bashrc
7 -fi
3 +# Copy all contents from /fs to root directory (/) without overwriting
4 +cp -rn --no-preserve=ownership,mode /fs/* /
5
9 -# Ensure .profile is in the root directory
10 -if [ ! -f /root/.profile ]; then
11 - cp /etc/skel/.bashrc /root/.profile
12 - chmod 444 /root/.profile
13 -fi
6 +# allow execution of /root/.bashrc and /root/.profile
7 +chmod 444 /root/.bashrc
8 +chmod 444 /root/.profile
9
10 +# update package list to save time later
11 apt-get update
12
13 +# Start A0
14 +bash /exe/run_A0.sh
15 +
16 # Start SSH service
18 -exec /usr/sbin/sshd -D
17 +exec /usr/sbin/sshd -D
\ No newline at end of file
run_ui.py
+8 -3
@@ -1,3 +1,4 @@
1 +import argparse
2 import json
3 from functools import wraps
4 import os
@@ -235,13 +236,13 @@ async def handle_message(sync: bool):
236 attachments = request.files.getlist('attachments')
237 attachment_paths = []
238
238 - upload_folder = os.path.join(os.getcwd(), 'work_dir', 'uploads')
239 + upload_folder = files.get_abs_path('work_dir/uploads')
240
241 if attachments:
242 os.makedirs(upload_folder, exist_ok=True)
243 for attachment in attachments:
244 filename = secure_filename(attachment.filename)
244 - save_path = os.path.join(upload_folder, filename)
245 + save_path = files.get_abs_path(upload_folder, filename)
246 attachment.save(save_path)
247 attachment_paths.append(save_path)
248 else:
@@ -570,8 +571,12 @@ def run():
571 def log_request(self, code="-", size="-"):
572 pass # Override to suppress request logging
573
574 + parser = argparse.ArgumentParser()
575 + parser.add_argument("--port", type=int, default=0, help="Web UI port")
576 + args = parser.parse_args()
577 +
578 # Get configuration from environment
574 - port = int(os.environ.get("WEB_UI_PORT", 0)) or None
579 + port = args.port or int(os.environ.get("WEB_UI_PORT", 0)) or None
580 host = os.environ.get("WEB_UI_HOST") or None
581 use_cloudflare = os.environ.get("USE_CLOUDFLARE", "false").lower() == "true"
582