This commit is contained in:
KaySar12 2025-04-04 08:47:01 +07:00
parent dbd5a8325c
commit ffc7cef059
7 changed files with 144 additions and 42 deletions

2
.gitignore vendored
View File

@ -6,7 +6,7 @@ __pycache__/
# C extensions
*.so
config/*.yaml
# Distribution / packaging
.Python
build/

22
cli.py
View File

@ -3,6 +3,7 @@ import argparse
import tqdm
from services.odoo.service import OdooServiceManager
from services.odoo.module import OdooModuleManager
import lib.color_log as color_log
def service(args):
@ -15,7 +16,10 @@ def service(args):
case "restart":
service.restart_service(args.instance)
case _:
print("Invalid action")
color_log.Show(
"FAILED",
f"Invalid action '{args.action}' for service management.",
)
def module(args):
@ -23,12 +27,17 @@ def module(args):
# If modules are provided in the command line
if args.modules:
print(f"Processing modules: {', '.join(args.modules)} for {args.instance}")
color_log.Show(
"INFO",
f"Processing modules: {', '.join(args.modules)} for {args.instance}",
)
else:
# Fallback if no modules are provided (can use default from instance settings)
print(f"No modules specified. Using default modules for {args.instance}")
color_log.Show(
"INFO",
f"No modules specified. Using default modules for {args.instance}",
)
args.modules = module_manager.get_modules(args.instance)
# Create a progress bar using tqdm
for module_name in tqdm.tqdm(
args.modules, desc="Processing modules", unit="module"
@ -41,7 +50,10 @@ def module(args):
case "upgrade":
module_manager.upgrade(args.instance, [module_name])
case _:
print("Invalid action")
color_log.Show(
"FAILED",
f"Invalid action '{args.action}' for module management.",
)
def setup_cli():

54
config/settings.template Normal file
View File

@ -0,0 +1,54 @@
odoo_instances:
- name: "ftacpa"
host: "10.1.1.31"
port: 8069
database: "ftacpa"
username: "nextzen"
password: "smartyourlife"
type: "systemctl"
service_name: "odoo18"
git:
repo_url: "https://hoangvv:smartyourlife@git.nextzenos.com/NextERP/Odoo18-FTACPA.git"
branch: "community/demo/ftacpa"
local_path: "/opt/odoo18/addons"
ssh:
user: root
password: Smartyourlife123@*
key_path: "/root/.ssh/privatessh.key"
odoo_instances:
- name: "ftacpa"
host: "10.1.1.31"
port: 8069
database: "server"
username: "nextzen"
password: "smartyourlife"
type: "systemctl"
service_name: "odoo18"
git:
repo_url: "https://hoangvv:smartyourlife@git.nextzenos.com/NextERP/Odoo18-FTACPA.git"
branch: "community/demo/ftacpa"
local_path: "/opt/ftacpa/addons"
ssh:
user: root
password: Smartyourlife123@*
key_path: "/root/.ssh/privatessh.key"
# - name: "server1_test"
# host: "server1.example.com"
# port: 8069
# database: "test_db1"
# username: "admin"
# password: "test_password"
# module_names:
# - "your_module"
# type: "docker"
# - name: "server2_prod"
# host: "server2.example.com"
# port: 8070
# database: "prod_db2"
# username: "admin"
# password: "admin_password"
# module_names:
# - "your_module"
# - "custom_module"
# - "third_module"
# type: "systemctl"

View File

@ -9,16 +9,16 @@ def colorize(text, code):
def Show(status, message):
"""Displays a message with a status indicator."""
colors = {
0: (
'OK': (
colorize("[", "90") + colorize(" OK ", "38;5;154") + colorize("]", "90")
), # Green, Grey
1: (
'FAILED': (
colorize("[", "90") + colorize(" FAILED ", "91") + colorize("]", "90")
), # Red, Grey
2: (
'INFO': (
colorize("[", "90") + colorize(" INFO ", "38;5;154") + colorize("]", "90")
), # Green, Grey
3: (
'WARNING': (
colorize("[", "90") + colorize(" WARNING ", "33") + colorize("]", "90")
), # Yellow, Grey
}

View File

@ -2,6 +2,7 @@ from odoorpc import ODOO
import os
import sys
from services.config import Config
import lib.color_log as color_log
class OdooConnection:
@ -48,11 +49,15 @@ class OdooConnection:
instance["database"], instance["username"], instance["password"]
)
self.connections[instance["name"]] = odoo
print(
f"Connected to {instance['host']}:{instance['port']} - {instance['database']}"
color_log.Show(
"OK",
f"Connected to {instance['name']} at {instance['host']}:{instance['port']}",
)
except Exception as e:
print(f"Failed to connect to {instance['name']}: {e}")
color_log.Show(
"FAILED",
f"Failed to connect to {instance['name']} at {instance['host']}:{instance['port']}: {e}",
)
raise
def get_connection(self, instance_name):
@ -69,7 +74,7 @@ class OdooConnection:
if name in self.connections:
# odoorpc doesn't have an explicit disconnect, so we just remove the reference
del self.connections[name]
print(f"Disconnected from instance: {name}")
color_log.Show("OK", f"Disconnected from {name}")
def get_instances(self):
"""Return the list of configured instances."""
@ -80,11 +85,13 @@ class OdooConnection:
odoo = self.get_connection(instance_name)
if not odoo:
raise ValueError(f"No connection available for instance '{instance_name}'")
try:
model_obj = odoo.env[model]
result = getattr(model_obj, method)(*args, **kwargs)
return result
except Exception as e:
print(f"Error executing {method} on {model} for {instance_name}: {e}")
color_log.Show(
"FAILED",
f"Error executing {method} on {model} for {instance_name}: {e}",
)
raise

View File

@ -1,6 +1,7 @@
from services.git.handler import GitHandler
from services.odoo.connection import OdooConnection
import subprocess
import lib.color_log as color_log
class OdooModuleManager:
@ -19,14 +20,13 @@ class OdooModuleManager:
for instance in self.config.get_instances():
if instance_name and instance["name"] != instance_name:
continue
print(f"Processing instance: {instance['name']}")
color_log.Show("INFO", f"Processing instance: {instance['name']}")
for module_name in module_names:
try:
print(
f"{action.capitalize()}ing module: {module_name} in {instance['name']}"
color_log.Show(
"INFO",
f"{action.capitalize()}ing module: {module_name} in {instance['name']}",
)
module_ids = self.config.execute(
instance["name"],
"ir.module.module",
@ -34,9 +34,10 @@ class OdooModuleManager:
[("name", "=", module_name)],
)
if not module_ids:
print(
f"Module {module_name} not found in {instance['name']}, skipping."
if not module_ids and action in ["upgrade", "uninstall"]:
color_log.Show(
"WARNING",
f"Module {module_name} not found in {instance['name']}, skipping.",
)
continue
@ -47,23 +48,41 @@ class OdooModuleManager:
button_action,
module_ids, # Pass list directly instead of wrapping in another list
)
print(
f"Module {module_name} {action}ed successfully in {instance['name']}"
color_log.Show(
"OK",
f"Module {module_name} {action}ed successfully in {instance['name']}",
)
except Exception as e:
print(
f"Error while {action}ing {module_name} in {instance['name']}: {e}"
color_log.Show(
"FAILED",
f"Error while {action}ing {module_name} in {instance['name']}: {e}",
)
def install(self, instance_name: str = None,module_names: list = None) -> None:
def get_modules(self, instance_name: str = None) -> list:
"""Get a list of installed modules for the specified instance(s)."""
self.config.connect(instance_name)
modules = []
for instance in self.config.get_instances():
if instance_name and instance["name"] != instance_name:
continue
color_log.Show("INFO", f"Fetching modules for instance: {instance['name']}")
module_ids = self.config.execute(
instance["name"],
"ir.module.module",
"search_read",
[],
["name"],
)
modules.extend([mod["name"] for mod in module_ids])
return modules
def install(self, instance_name: str = None, module_names: list = None) -> None:
"""Install multiple modules for the specified instance(s)."""
self._manage_module("install", instance_name,module_names)
self._manage_module("install", instance_name, module_names)
def uninstall(self, instance_name: str = None,module_names: list = None) -> None:
def uninstall(self, instance_name: str = None, module_names: list = None) -> None:
"""Uninstall multiple modules for the specified instance(s)."""
self._manage_module("uninstall", instance_name,module_names)
self._manage_module("uninstall", instance_name, module_names)
def upgrade(self, instance_name: str = None,module_names: list = None) -> None:
def upgrade(self, instance_name: str = None, module_names: list = None) -> None:
"""Upgrade multiple modules for the specified instance(s)."""
self._manage_module("upgrade", instance_name,module_names)
self._manage_module("upgrade", instance_name, module_names)

View File

@ -1,5 +1,6 @@
import subprocess
from services.odoo.connection import OdooConnection
import lib.color_log as color_log
class OdooServiceManager:
@ -9,11 +10,15 @@ class OdooServiceManager:
def _execute_command(self, cmd, instance_name):
"""Execute a shell command and handle errors."""
try:
print(f"Executing: {cmd}")
color_log.Show("INFO", f"Executing command: {cmd}")
subprocess.run(cmd, shell=True, check=True, capture_output=True, text=True)
print(f"Service operation successful for {instance_name}")
color_log.Show("OK", f"Command executed successfully for {instance_name}")
except subprocess.CalledProcessError as e:
print(f"Error performing service operation for {instance_name}: {e}")
color_log.Show(
"FAILED",
f"Error performing service operation for {instance_name}: {e}",
)
raise
def _get_command(self, instance, action):
@ -35,7 +40,10 @@ class OdooServiceManager:
container_name = instance.get("container_name", f"odoo_{instance['name']}")
cmd = f"docker {action} {container_name}"
else:
print(f"Unsupported service type '{service_type}' for {instance['name']}")
color_log.Show(
"WARNING",
f"Unsupported service type '{service_type}' for {instance['name']}",
)
return None
if not local_host:
@ -52,14 +60,16 @@ class OdooServiceManager:
:param action: "stop" or "restart"
:param instance_name: Specific instance name, or None for all instances.
"""
if action not in ["stop", "restart","start"]:
if action not in ["stop", "restart", "start"]:
raise ValueError("Action must be 'stop' or 'restart'.")
for instance in self.config.get_instances():
if instance_name and instance["name"] != instance_name:
continue
print(f"{action.capitalize()}ing service for instance: {instance['name']}")
color_log.Show(
"INFO",
f"{action.capitalize()}ing service for instance: {instance['name']}",
)
cmd = self._get_command(instance, action)
if cmd:
self._execute_command(cmd, instance["name"])