-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
346 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
name: MOR Agents Build Linux | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
workflow_dispatch: | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
submodules: 'recursive' | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: '3.12' | ||
|
||
- name: Install dependencies | ||
run: | | ||
python -m pip install --upgrade pip | ||
pip install -r requirements.txt | ||
pip install pyinstaller | ||
- name: Build with PyInstaller | ||
run: | | ||
pyinstaller --name="MORagents" --add-data "images/moragents.png:images" main.py | ||
- name: Create Debian package | ||
run: | | ||
mkdir -p debian/DEBIAN | ||
mkdir -p debian/usr/bin | ||
mkdir -p debian/usr/share/applications | ||
mkdir -p debian/usr/share/icons/hicolor/256x256/apps | ||
cp -r dist/MORagents/* debian/usr/bin/ | ||
cp images/moragents.png debian/usr/share/icons/hicolor/256x256/apps/moragents.png | ||
echo "[Desktop Entry] | ||
Name=MORagents | ||
Exec=/usr/bin/MORagents | ||
Icon=moragents | ||
Type=Application | ||
Categories=Utility;" > debian/usr/share/applications/moragents.desktop | ||
echo "Package: moragents | ||
Version: 1.0 | ||
Section: utils | ||
Priority: optional | ||
Architecture: amd64 | ||
Maintainer: LachsBagel | ||
Description: MORagents application | ||
MORagents is a desktop application for AI agents." > debian/DEBIAN/control | ||
dpkg-deb --build debian moragents.deb | ||
- name: Create setup script | ||
run: | | ||
cat << EOF > moragents-setup.sh | ||
#!/bin/bash | ||
set -e | ||
# Colors for output | ||
GREEN='\033[0;32m' | ||
YELLOW='\033[0;33m' | ||
NC='\033[0m' # No Color | ||
# Function to check if a command exists | ||
command_exists() { | ||
command -v "$1" >/dev/null 2>&1 | ||
} | ||
# Function to add current user to docker group | ||
add_user_to_docker_group() { | ||
local current_user=\$(whoami) | ||
if [ "\$current_user" != "root" ]; then | ||
echo -e "\${YELLOW}Adding current user to docker group...${NC}" | ||
sudo usermod -aG docker "\$current_user" | ||
echo -e "\${GREEN}User added to docker group. Please log out and log back in for changes to take effect.${NC}" | ||
else | ||
echo -e "\${YELLOW}Running as root. Skipping user addition to docker group.${NC}" | ||
fi | ||
} | ||
# Install curl if not present | ||
if ! command_exists curl; then | ||
echo -e "${YELLOW}Installing curl...${NC}" | ||
sudo apt-get update | ||
sudo apt-get install -y curl | ||
fi | ||
# Install Docker if not present | ||
if ! command_exists docker; then | ||
echo -e "${YELLOW}Installing Docker...${NC}" | ||
curl -fsSL https://get.docker.com -o get-docker.sh | ||
sudo sh get-docker.sh | ||
add_user_to_docker_group | ||
sudo systemctl enable docker | ||
sudo systemctl start docker | ||
else | ||
echo -e "${GREEN}Docker is already installed.${NC}" | ||
fi | ||
# Install Ollama | ||
echo -e "${YELLOW}Installing Ollama...${NC}" | ||
curl -fsSL https://ollama.com/install.sh | sh | ||
# Start Ollama service | ||
echo -e "${YELLOW}Starting Ollama service...${NC}" | ||
nohup ollama serve > /dev/null 2>&1 & | ||
# Pull Ollama models | ||
echo -e "${YELLOW}Pulling Ollama models...${NC}" | ||
ollama pull llama3 | ||
ollama pull nomic-embed-text | ||
# Pull necessary Docker images | ||
echo -e "${YELLOW}Pulling Docker images...${NC}" | ||
sudo docker pull lachsbagel/moragents_dockers-nginx:amd64-0.0.9 | ||
sudo docker pull lachsbagel/moragents_dockers-agents:amd64-0.0.9 | ||
# Start Docker containers | ||
echo -e "${YELLOW}Starting Docker containers...${NC}" | ||
sudo docker run -d --name agents -p 8080:5000 --restart always -v /var/lib/agents -v /app/src lachsbagel/moragents_dockers-agents:amd64-0.0.9 | ||
sudo docker run -d --name nginx -p 3333:80 lachsbagel/moragents_dockers-nginx:amd64-0.0.9 | ||
echo -e "${GREEN}Setup complete!${NC}" | ||
EOF | ||
chmod +x moragents-setup.sh | ||
- name: Upload Debian Package and Setup Script | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: MORagentsSetup-Linux | ||
path: | | ||
moragents.deb | ||
moragents-setup.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/bin/bash | ||
|
||
# Colors for output | ||
RED='\033[0;31m' | ||
GREEN='\033[0;32m' | ||
YELLOW='\033[0;33m' | ||
NC='\033[0m' # No Color | ||
|
||
# Check if script is run as root | ||
if [ "$EUID" -ne 0 ]; then | ||
echo -e "${RED}Please run as root${NC}" | ||
exit 1 | ||
fi | ||
|
||
echo -e "${GREEN}Welcome to the MORagents installer for Linux${NC}" | ||
|
||
# Install the .deb package | ||
echo -e "${YELLOW}Installing MORagents...${NC}" | ||
dpkg -i moragents.deb | ||
apt-get install -f -y | ||
|
||
# Run the setup script | ||
echo -e "${YELLOW}Running MORagents setup...${NC}" | ||
./moragents-setup.sh | ||
|
||
echo -e "${GREEN}Installation complete!${NC}" | ||
echo "You can now start MORagents from your application menu or by running 'MORagents' in the terminal." | ||
echo -e "${YELLOW}NOTE: Please log out and log back in for Docker group changes to take effect.${NC}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
import os | ||
import shutil | ||
import subprocess | ||
|
||
from utils.logger_config import setup_logger | ||
from config import AgentDockerConfig, AgentDockerConfigDeprecate | ||
|
||
logger = setup_logger(__name__) | ||
|
||
def get_docker_path(): | ||
docker_paths = [ | ||
'/usr/bin/docker', # Common Linux path | ||
'/usr/local/bin/docker', # Alternative Linux path | ||
shutil.which('docker') | ||
] | ||
for docker_path in docker_paths: | ||
if docker_path and os.path.exists(docker_path): | ||
return docker_path | ||
|
||
logger.error("Docker executable not found in PATH.") | ||
return None | ||
|
||
def check_docker_installed(docker_path): | ||
try: | ||
subprocess.run([docker_path, "--version"], | ||
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | ||
logger.info(f"Docker was found at {docker_path}") | ||
return True | ||
except (subprocess.CalledProcessError, TypeError) as e: | ||
logger.error(f"Error checking Docker installation: {str(e)}") | ||
return False | ||
|
||
def delete_docker_image(docker_path, image_name): | ||
try: | ||
# List all images | ||
list_command = [docker_path, "images", "--format", "{{.Repository}}:{{.Tag}}"] | ||
output = subprocess.check_output(list_command, universal_newlines=True) | ||
images = output.strip().split("\n") | ||
|
||
# Find the image with the specified name | ||
if image_name in images: | ||
# Remove the image | ||
remove_command = [docker_path, "rmi", "-f", image_name] | ||
subprocess.run(remove_command, check=True) | ||
logger.info(f"Image '{image_name}' deleted successfully.") | ||
else: | ||
pass | ||
|
||
except subprocess.CalledProcessError as e: | ||
logger.warning(f"Error deleting image: {e}") | ||
|
||
def list_containers_for_image(docker_path, image_name): | ||
try: | ||
output = subprocess.check_output( | ||
[docker_path, "ps", "-a", "--filter", f"ancestor={image_name}", "--format", "{{.ID}}"]) | ||
containers = output.decode().strip().split("\n") | ||
return [container for container in containers if container] | ||
except subprocess.CalledProcessError as e: | ||
logger.error(f"Failed to list containers for image '{image_name}': {e}") | ||
return [] | ||
|
||
def remove_container(docker_path, container): | ||
try: | ||
subprocess.run([docker_path, "rm", "-f", container], check=True, stdout=subprocess.DEVNULL, | ||
stderr=subprocess.DEVNULL) | ||
except subprocess.CalledProcessError as e: | ||
logger.error(f"Failed to remove container '{container}': {e}") | ||
|
||
def docker_image_present_on_host(docker_path, image_name): | ||
try: | ||
subprocess.run([docker_path, "inspect", image_name], check=True, stdout=subprocess.DEVNULL, | ||
stderr=subprocess.DEVNULL) | ||
return True | ||
except (subprocess.CalledProcessError, TypeError) as e: | ||
return False | ||
|
||
def remove_containers_for_image(docker_path, image_name): | ||
containers = list_containers_for_image(docker_path, image_name) | ||
for container in containers: | ||
remove_container(docker_path, container) | ||
logger.info(f"Removed container '{container}' for image '{image_name}'") | ||
|
||
def remove_containers_by_name(docker_path, container_name): | ||
try: | ||
list_command = [docker_path, "ps", "-a", "--format", "{{.Names}}"] | ||
output = subprocess.check_output(list_command, universal_newlines=True) | ||
containers = output.strip().split("\n") | ||
|
||
if container_name in containers: | ||
remove_command = [docker_path, "rm", "-f", container_name] | ||
subprocess.run(remove_command, check=True) | ||
logger.info(f"Removed container '{container_name}'") | ||
else: | ||
logger.info(f"Container '{container_name}' not found") | ||
except subprocess.CalledProcessError as e: | ||
logger.error(f"Error removing container '{container_name}': {str(e)}") | ||
|
||
def migration_remove_old_images(docker_path): | ||
for image_name in AgentDockerConfigDeprecate.OLD_IMAGE_NAMES: | ||
if docker_image_present_on_host(docker_path, image_name): | ||
delete_docker_image(docker_path, image_name) | ||
logger.info(f"Deleted image '{image_name} from previous release") | ||
|
||
def pull_docker_images(docker_path): | ||
for image in AgentDockerConfig.get_current_image_names(): | ||
try: | ||
subprocess.run([docker_path, "pull", image], check=True) | ||
logger.info(f"Successfully pulled image: {image}") | ||
except subprocess.CalledProcessError as e: | ||
logger.error(f"Failed to pull image {image}: {e}") | ||
raise | ||
|
||
def start_ollama_server(): | ||
ollama_path = '/usr/local/bin/ollama' # This path might need to be adjusted for Linux | ||
|
||
try: | ||
# Start Ollama server | ||
logger.info("Starting Ollama server...") | ||
subprocess.Popen([ollama_path, "serve"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) | ||
logger.info("Ollama server started successfully.") | ||
except Exception as e: | ||
logger.info("Failed to start Ollama server.") | ||
logger.error(f"Failed to start Ollama server: {e}") | ||
|
||
def docker_setup(): | ||
docker_path = get_docker_path() | ||
logger.info(f"Docker path: {docker_path}") | ||
|
||
if not check_docker_installed(docker_path): | ||
logger.critical("Docker is not installed.") | ||
raise RuntimeError("Docker is not installed.") | ||
|
||
# Remove old images and containers | ||
logger.info("Checking whether old images need removal.") | ||
migration_remove_old_images(docker_path) | ||
|
||
for image_name in AgentDockerConfig.get_current_image_names(): | ||
remove_containers_for_image(docker_path, image_name) | ||
|
||
remove_containers_by_name(docker_path, "agents") | ||
remove_containers_by_name(docker_path, "nginx") | ||
|
||
# Pull the latest images | ||
pull_docker_images(docker_path) | ||
|
||
# Spin up Agent container | ||
subprocess.run([ | ||
docker_path, "run", "-d", "--name", "agents", | ||
"-p", "8080:5000", "--restart", "always", | ||
"-v", "/var/lib/agents:/var/lib/agents", "-v", "/app/src:/app/src", # Adjusted volume paths for Linux | ||
AgentDockerConfig.get_current_image_names()[1] # agents image | ||
], check=True) | ||
|
||
# Spin up Nginx container | ||
subprocess.run([ | ||
docker_path, "run", "-d", "--name", "nginx", "-p", "3333:80", | ||
AgentDockerConfig.get_current_image_names()[0] # nginx image | ||
], check=True) | ||
|
||
def main(): | ||
# main() called every time the app is opened (from main.py). Put all app open code here. | ||
logger.info("Starting app...") | ||
start_ollama_server() | ||
docker_setup() | ||
|
||
if __name__ == "__main__": | ||
main() |