Browse Source

[ADD] all steps

robert 6 years ago
parent
commit
7114693595
6 changed files with 334 additions and 79 deletions
  1. 2 0
      models/__init__.py
  2. BIN
      models/__init__.pyc
  3. 297 79
      models/odoo_instance.py
  4. 13 0
      models/odoo_module.py
  5. 9 0
      models/odoo_module_package.py
  6. 13 0
      models/server.py

+ 2 - 0
models/__init__.py

@@ -1,4 +1,6 @@
 # -*- coding: utf-8 -*-
 import payment_plan
 import odoo_instance
+import odoo_module
+import odoo_module_package
 import odoo_management_config

BIN
models/__init__.pyc


+ 297 - 79
models/odoo_instance.py

@@ -1,10 +1,24 @@
 # -*- coding: utf-8 -*-
 from openerp import models, fields, api
+from openerp.tools import email_send
 from openerp.exceptions import Warning, ValidationError
 from jinja2 import Environment as JinjaEnv, PackageLoader as JinjaLoader
-from ..utils.docker_api import get_all_external_ports
-from ..utils.command import execute
+from ..utils.docker_api import (
+    get_all_external_ports,
+    run_command,
+    copy_in,
+    run_container,
+    get_internal_ip,
+    get_status,
+    stop_container,
+    start_container,
+    restart_container
+)
+from ..utils.command import execute, list_files_and_folders
 from random import randint
+from git.util import join_path
+from git.repo.base import Repo
+from git.exc import GitCommandError
 import unicodedata
 import stringcase
 import time
@@ -50,27 +64,28 @@ class OdooInstance(models.Model):
         if len(name) == 0:
             return False
 
-        root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
+        root_path = self.env['odoo.management.config'].get_default_settings([]).get('odoo_root_path')
 
         if len(root_path) == 0:
             raise Warning('La ruta por defecto para los sistemas no está definido')
 
         full_path = os.path.join(root_path, name)
 
-        return os.path.exists(full_path)
+        return not os.path.exists(full_path)
 
     def _randomize_port(self):
-        ports = self.env['ir.values'].get_default(self._name, 'odoo_ports_range')
+        ports = self.env['odoo.management.config'].get_default_settings([]).get('odoo_ports_range')
         ports = filter(lambda x: x != '', ports.split(','))
 
         if len(ports) == 0:
-            raise Warning('El rango de puertos para los sistemas no está definido')
+            ports = [10000, 20000]
+            # raise Warning('El rango de puertos para los sistemas no está definido')
 
         port = 0
 
         while not self._check_port_availability(port):
             port = randint(ports[0], ports[1])
-            time.sleep(1)
+            time.sleep(0.05)
 
         return port
 
@@ -80,7 +95,11 @@ class OdooInstance(models.Model):
         for d in self.DEFAULT_DIRS:
             full_path = os.path.join(root_path, name, d.strip())
             os.makedirs(full_path)
-            time.sleep(1)
+
+    def _delete_dirs(self, name):
+        root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
+        full_path = os.path.join(root_path, name)
+        execute(['rm', '-Rf', full_path])
 
     def _make_config_file(self, name):
         root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
@@ -106,9 +125,159 @@ class OdooInstance(models.Model):
     def _create_database(self, name):
         odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
         cmd = 'createdb -U %s %s' % ('odoo', name)
+        output = run_command(odoo_db, cmd)
+
+        return output
+
+    def _drop_database(self, name):
+        odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
+
+        terminate_cmd = "psql -U %s select pg_terminate_backend(pid) from pg_stats where datname = '%s'" % ('odoo', name)
+        run_command(odoo_db, terminate_cmd)
+
+        drop_cmd = 'drop database %s' % name
+        run_command(odoo_db, drop_cmd)
+
+    def _copy_database_seed(self):
+        odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
+        backup_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'files', 'odoo.tar')
+        output = copy_in(odoo_db, '/tmp', backup_path)
+
+        return output
+
+    def _restore_database(self, name):
+        odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
+        cmd = 'psql -U %s -d %s -f %s' % (odoo_db, name, '/tmp/odoo.sql')
+        output = run_command(odoo_db, cmd)
+
+        return output
+
+    def _remove_database_seed(self):
+        odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
+        cmd = 'rm -f %s' % '/tmp/odoo.sql'
+        output = run_command(odoo_db, cmd)
+
+        return output
+
+    def _create_container(self, name, ports=[]):
+        ir_values = self.env['ir.values']
+
+        root_path = ir_values.get_default(self._name, 'odoo_root_path')
+        odoo_docker_image = ir_values.get_default(self._name, 'odoo_docker_image')
+        odoo_network = ir_values.get_default(self._name, 'odoo_network')
+
+        ports = dict(map(lambda p: ('%d/tcp' % 8069, p), ports))
+        volumes = dict()
+
+        run_container(
+            odoo_docker_image,
+            name,
+            ports,
+            volumes,
+            odoo_network,
+            '150m',
+            '150m'
+        )
+
+        time.sleep(3)
+
+        return True
+
+    def _apply_permissions(self, name):
+        root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
+        full_path = os.path.join(root_path, name)
+        execute(['chmod', '-Rf', '777'], full_path)
+
+        return True
+
+    def _get_internal_ip(self, name):
+        return get_internal_ip(name)
+
+    def _clone_repositories(self, names=[], path=None, branch='master'):
+        if len(names) == 0 or not path:
+            return False
+
+        git_path = self.env['ir.values'].get_default(self._name, 'modules_git_path')
+        paths = list_files_and_folders(git_path)
+
+        if len(git_path) == 0:
+            raise Warning('La ruta por defecto del repositorio no está definido')
+
+        for path in paths:
+            for name in names:
+                repo_path = '%s.git' % join_path(git_path, path, name)
+
+                if not os.path.exists(repo_path):
+                    continue
+
+                try:
+                    repo = Repo(repo_path)
+                    repo.clone(join_path(path, name), branch=branch)
+                    repo.close()
+                except GitCommandError:
+                    pass
+
+        return True
+
+    def _clone_repository(self, name, path):
+        result = self._clone_repositories([name], path)
+
+        return result
+
+    def _copy_modules(self, name, modules=[]):
+        root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
+
+        if not os.path.exists(root_path):
+            raise Warning('El directorio del sistema no existe')
+
+        container_is_running = get_status(name)
+
+        if container_is_running:
+            stopped = stop_container(name)
+
+            if not stopped:
+                raise Warning('No se pudo parar el contenedor')
+
+        for module in modules:
+            module_path = os.path.join(root_path, 'custom-addons', module)
+
+            if os.path.exists(module_path):
+                execute(['rm', '-Rf', module_path])
+
+            addons_path = os.path.join(root_path, 'custom-addons')
+            self._clone_repository(module, addons_path)
 
-        return execute(cmd)
+            git_data_path = os.path.join(module, '.git')
 
+            if os.path.exists(git_data_path):
+                execute(['rm', '-Rf', git_data_path])
+
+            try:
+                execute(['chmod', '-Rf', '777', module_path])
+            except Exception:
+                pass
+
+        if container_is_running:
+            started = start_container(name)
+
+            if not started:
+                raise Warning('No se pudo arrancar el contenedor')
+
+    def _copy_module(self, name, module):
+        self._copy_modules(name, [module])
+
+    # def _handle_container_event(self, e):
+    #     event_type = e.get('Type')
+    #     event_action = e.get('Action')
+    #     container_id = e.get('Actor').get('ID')
+    #
+    #     print(event_type)
+    #     print(event_action)
+    #     print(container_id)
+    #
+    # def _register_hook(self, cr):
+    #     run_watchdog(self._handle_container_event)
+    #     super(OdooInstance, self)._register_hook(cr)
 
     name = fields.Char(string='Nombre', size=50)
     normalized_name = fields.Char(string='Nombre normalizado', compute='_normalize_name', size=50)
@@ -124,6 +293,9 @@ class OdooInstance(models.Model):
     running = fields.Boolean(string='Está online?', default=False)
     payment_plan_id = fields.Many2one(string='Plan de pago', comodel_name='payment.plan', required=True)
 
+    def _send_email(self, ):
+        email_send()
+
     @api.model
     def create(self, values):
         snaked_name = self._snakeike_name(values.get('name'))
@@ -132,7 +304,7 @@ class OdooInstance(models.Model):
         if not name_is_available:
             raise ValidationError('El nombre ya está siendo usado por otro sistema')
 
-        return super(self, OdooInstance).create(values)
+        return super(OdooInstance, self).create(values)
 
     @api.one
     @api.onchange('name')
@@ -150,74 +322,72 @@ class OdooInstance(models.Model):
         if self.state not in ('draft', 'suspended'):
             raise Warning('No se puede activar un sistema ya activo')
 
-        self._check_name_availability(self.normalized_name)
-
-        # # 1. Check name
-        # name_is_available = odoo_api.check_name_availability(self.normalized_name)
-        #
-        # if not name_is_available:
-        #     raise Warning('El nombre ya está siendo usado por otro sistema')
-        #
-        # # 2. Get a port
-        # port_to_use = odoo_api.randomize_port()
-        #
-        # # 3. Create dirs
-        # make_ok = odoo_api.make_default_dirs(self.normalized_name)
-        #
-        # if not make_ok:
-        #     raise Warning('No se pudo crear la estructura de directorios')
-        #
-        # # 4. Create configuration file
-        # config_ok = odoo_api.make_config_file(self.normalized_name)
-        #
-        # if not config_ok:
-        #     raise Warning('No se pudo crear el archivo de configuración')
-        #
-        # # 5. Create database
-        # db_ok = odoo_api.create_database(self.normalized_name)
-        #
-        # if not db_ok:
-        #     raise Warning('No se pudo crear la base de datos')
-        #
-        # # 6. Copy database seed
-        # seed_copied = odoo_api.copy_database_seed()
-        #
-        # if not seed_copied:
-        #     raise Warning('No se pudo copiar la estructura inicial de la base de datos')
-        #
-        # # 7. Restore database schema
-        # restored = odoo_api.restore_database(self.normalized_name)
-        #
-        # if not restored:
-        #     raise Warning('No se pudo reestablecer la copia de base de datos')
-        #
-        # # 8. Remove database seed
-        # seed_removed = odoo_api.remove_database_seed()
-        #
-        # if not seed_removed:
-        #     raise Warning('No se pudo remover la copia de base de datos')
-        #
-        # # 9. Create odoo container
-        # odoo_created = odoo_api.create_container(self.normalized_name, [port_to_use])
-        #
-        # if not odoo_created:
-        #     raise Warning('No se pudo crear el contenedor')
-        #
-        # # 10. Apply permissions
-        # permissions_applied = odoo_api.apply_permissions(self.normalized_name)
-        #
-        # if not permissions_applied:
-        #     raise Warning('No se pudo aplicar los permisos correspondientes')
-        #
-        # # 11. Get internal ip
-        # internal_ip = odoo_api.get_internal_ip(self.normalized_name)
-        #
-        # # 12. Send email
-        # # TODO
-        #
-        # print(internal_ip)
-        #
-        # self.state = 'activated'
+        # 1. Check name
+        name_is_available = self._check_name_availability(self.normalized_name)
+
+        if not name_is_available:
+            raise Warning('El nombre ya está siendo usado por otro sistema')
+
+        # 2. Get a port
+        port_to_use = self._randomize_port()
+
+        # 3. Create dirs
+        make_ok = self.make_default_dirs(self.normalized_name)
+
+        if not make_ok:
+            raise Warning('No se pudo crear la estructura de directorios')
+
+        # 4. Create configuration file
+        config_ok = self.make_config_file(self.normalized_name)
+
+        if not config_ok:
+            raise Warning('No se pudo crear el archivo de configuración')
+
+        # 5. Create database
+        db_ok = self.create_database(self.normalized_name)
+
+        if not db_ok:
+            raise Warning('No se pudo crear la base de datos')
+
+        # 6. Copy database seed
+        seed_copied = self.copy_database_seed()
+
+        if not seed_copied:
+            raise Warning('No se pudo copiar la estructura inicial de la base de datos')
+
+        # 7. Restore database schema
+        restored = self.restore_database(self.normalized_name)
+
+        if not restored:
+            raise Warning('No se pudo reestablecer la copia de base de datos')
+
+        # 8. Remove database seed
+        seed_removed = self.remove_database_seed()
+
+        if not seed_removed:
+            raise Warning('No se pudo remover la copia de base de datos')
+
+        # 9. Create odoo container
+        odoo_created = self.create_container(self.normalized_name, [port_to_use])
+
+        if not odoo_created:
+            raise Warning('No se pudo crear el contenedor')
+
+        # 10. Apply permissions
+        permissions_applied = self.apply_permissions(self.normalized_name)
+
+        if not permissions_applied:
+            raise Warning('No se pudo aplicar los permisos correspondientes')
+
+        # 11. Get internal ip
+        internal_ip = self.get_internal_ip(self.normalized_name)
+
+        # 12. Send email
+        # TODO
+
+        print(internal_ip)
+
+        self.state = 'activated'
 
     @api.one
     def action_disapprove(self):
@@ -231,18 +401,42 @@ class OdooInstance(models.Model):
         if self.state != 'activated':
             raise Warning('No se puede suspender un sistema no activo')
 
+        # 1. Get container status and stop it
+        container_is_running = get_status(self.normalized_name)
+
+        if container_is_running:
+            stopped = stop_container(self.normalized_name)
+
+            if not stopped:
+                raise Warning('No se pudo parar el contenedor %s' % self.normalized_name)
+
         self.state = 'suspended'
         self.running = False
 
     @api.one
     def copy(self):
-        raise Warning('Atención', 'No se puede duplicar una instancia. Por favor, cree uno nuevo')
+        raise Warning('Atención', 'Está prohibido duplicar una instancia. Por favor, cree uno nuevo')
 
     @api.one
     def action_destroy(self):
         if self.state == 'destroyed':
             raise Warning('No se puede eliminar un sistema ya eliminado')
 
+        # 1. Get container status and stop it if necessary
+        container_is_running = get_status(self.normalized_name)
+
+        if container_is_running:
+            stopped = stop_container(self.normalized_name)
+
+            if not stopped:
+                raise Warning('Atención', 'No se pudo parar el contenedor %s' % self.normalized_name)
+
+        # 2. Delete dirs
+        self._delete_dirs(self.normalized_name)
+
+        # 3. Drop database
+        self._drop_database(self.normalized_name)
+
         self.state = 'destroyed'
         self.running = False
 
@@ -251,6 +445,18 @@ class OdooInstance(models.Model):
         if self.running:
             raise Warning('Atención', 'No se puede arrancar una instancia que ya está arrancada')
 
+        # 1. Get container status
+        container_is_running = get_status(self.normalized_name)
+
+        if container_is_running:
+            raise Warning('Atención', 'No se puede arrancar una instancia que ya está arrancada')
+
+        # 2. Start container
+        started = start_container(self.normalized_name)
+
+        if not started:
+            raise Warning('Atención', 'No se pudo arrancar el contenedor')
+
         self.running = True
 
     @api.one
@@ -258,6 +464,18 @@ class OdooInstance(models.Model):
         if not self.running:
             raise Warning('Atención', 'No se puede parar y arrancar una instancia que ya está parada')
 
+        # 1. Get container status
+        container_is_running = get_status(self.normalized_name)
+
+        if not container_is_running:
+            raise Warning('Atención', 'No se puede parar y arrancar una instancia que ya está parada')
+
+        # 2. Restart container
+        restarted = restart_container(self.normalized_name)
+
+        if not restarted:
+            raise Warning('Atención', 'No se pudo reiniciar el contenedor')
+
         self.running = True
 
     @api.model

+ 13 - 0
models/odoo_module.py

@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+from openerp import models, fields
+
+
+class OdooModule(models.Model):
+    _name = 'odoo.module'
+
+    def _read_modules(self):
+        pass
+
+    name = fields.Char(string='Nombre', size=100)
+    technical_name = fields.Char(string='Nombre Técnico', size=100)
+    author = fields.Char(string='Nombre Técnico', size=160)

+ 9 - 0
models/odoo_module_package.py

@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+from openerp import models, fields
+
+
+class OdooModulePackage(models.Model):
+    _name = 'odoo.module.package'
+
+    name = fields.Char(string='Nombre', size=100)
+    # module_ids = fields.One2many(string='Módulos', comodel_name='odoo.module')

+ 13 - 0
models/server.py

@@ -0,0 +1,13 @@
+# -*- coding: utf-8 -*-
+from openerp.service.server import ThreadedServer
+
+
+class ThreadedServerOptimized(ThreadedServer):
+
+    def __init__(self, app):
+        super(ThreadedServer, self).__init__(app)
+
+    def start(self, stop=False):
+        super(ThreadedServer, self).start(stop)
+
+        print ('monitoring')