odoo_instance.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # -*- coding: utf-8 -*-
  2. from openerp import models, fields, api
  3. from openerp.exceptions import Warning, ValidationError
  4. from jinja2 import Environment as JinjaEnv, PackageLoader as JinjaLoader
  5. from ..utils.docker_api import get_all_external_ports
  6. from ..utils.command import execute
  7. from random import randint
  8. import unicodedata
  9. import stringcase
  10. import time
  11. import os
  12. class OdooInstance(models.Model):
  13. _name = 'odoo.instance'
  14. CONTAINER_STATUS = [
  15. ('draft', 'Por activar'),
  16. ('activated', 'Activado'),
  17. ('disapproved', 'No aprobado'),
  18. ('suspended', 'Suspendido'),
  19. ('destroyed', 'Eliminado')
  20. ]
  21. DEFAULT_DIRS = [
  22. 'config',
  23. 'custom-addons',
  24. 'files'
  25. ]
  26. # 'config: /etc/odoo, custom-addons: /mnt/extra-addons, files: /var/lib/odoo'
  27. def _snakeike_name(self, name):
  28. try:
  29. name = unicodedata.normalize('NFKD', name)
  30. name = name.encode('ASCII', 'ignore')
  31. except TypeError:
  32. pass
  33. name = stringcase.trimcase(name)
  34. name = stringcase.lowercase(name)
  35. name = stringcase.snakecase(name)
  36. return name
  37. def _check_port_availability(self, port):
  38. return port not in get_all_external_ports()
  39. def _check_name_availability(self, name):
  40. if len(name) == 0:
  41. return False
  42. root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
  43. if len(root_path) == 0:
  44. raise Warning('La ruta por defecto para los sistemas no está definido')
  45. full_path = os.path.join(root_path, name)
  46. return os.path.exists(full_path)
  47. def _randomize_port(self):
  48. ports = self.env['ir.values'].get_default(self._name, 'odoo_ports_range')
  49. ports = filter(lambda x: x != '', ports.split(','))
  50. if len(ports) == 0:
  51. raise Warning('El rango de puertos para los sistemas no está definido')
  52. port = 0
  53. while not self._check_port_availability(port):
  54. port = randint(ports[0], ports[1])
  55. time.sleep(1)
  56. return port
  57. def _make_default_dirs(self, name):
  58. root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
  59. for d in self.DEFAULT_DIRS:
  60. full_path = os.path.join(root_path, name, d.strip())
  61. os.makedirs(full_path)
  62. time.sleep(1)
  63. def _make_config_file(self, name):
  64. root_path = self.env['ir.values'].get_default(self._name, 'odoo_root_path')
  65. config_path = os.path.join(root_path, name, 'config')
  66. if not os.path.exists(config_path):
  67. raise Warning('No se creó el directorio para el archivo de configuración')
  68. env = JinjaEnv(loader=JinjaLoader('assets', 'templates'))
  69. tmpl = env.get_template('openerp-server.j2')
  70. tmpl_rendered = tmpl.stream({
  71. 'admin_password': 'admin',
  72. 'db_host': '',
  73. 'db_port': '',
  74. 'db_name': '',
  75. 'db_user': '',
  76. 'db_password': ''
  77. })
  78. tmpl_rendered.dump(os.path.join(config_path, 'openerp-config.conf'))
  79. def _create_database(self, name):
  80. odoo_db = self.env['ir.values'].get_default(self._name, 'odoo_db_link')
  81. cmd = 'createdb -U %s %s' % ('odoo', name)
  82. return execute(cmd)
  83. name = fields.Char(string='Nombre', size=50)
  84. normalized_name = fields.Char(string='Nombre normalizado', compute='_normalize_name', size=50)
  85. logo = fields.Binary(string='Logo')
  86. internal_ip = fields.Char(string='IP interno', size=15)
  87. internal_port = fields.Integer(string='Puerto interno')
  88. external_ip = fields.Char(string='IP externo', size=15)
  89. external_port = fields.Integer(string='Puerto externo')
  90. expose_ip = fields.Boolean(string='Exponer IP', default=True)
  91. state = fields.Selection(string='Estado', selection=CONTAINER_STATUS, default='draft')
  92. demo = fields.Boolean(string='Es un demo?', default=False)
  93. domain = fields.Char(string='Dominio', size=100)
  94. running = fields.Boolean(string='Está online?', default=False)
  95. payment_plan_id = fields.Many2one(string='Plan de pago', comodel_name='payment.plan', required=True)
  96. @api.model
  97. def create(self, values):
  98. snaked_name = self._snakeike_name(values.get('name'))
  99. name_is_available = self._check_name_availability(snaked_name)
  100. if not name_is_available:
  101. raise ValidationError('El nombre ya está siendo usado por otro sistema')
  102. return super(self, OdooInstance).create(values)
  103. @api.one
  104. @api.onchange('name')
  105. def _onchange_name(self):
  106. if self.name:
  107. self.name = self.name.title()
  108. @api.one
  109. @api.depends('name')
  110. def _normalize_name(self):
  111. self.normalized_name = self._snakeike_name(self.name)
  112. @api.one
  113. def action_activate(self):
  114. if self.state not in ('draft', 'suspended'):
  115. raise Warning('No se puede activar un sistema ya activo')
  116. self._check_name_availability(self.normalized_name)
  117. # # 1. Check name
  118. # name_is_available = odoo_api.check_name_availability(self.normalized_name)
  119. #
  120. # if not name_is_available:
  121. # raise Warning('El nombre ya está siendo usado por otro sistema')
  122. #
  123. # # 2. Get a port
  124. # port_to_use = odoo_api.randomize_port()
  125. #
  126. # # 3. Create dirs
  127. # make_ok = odoo_api.make_default_dirs(self.normalized_name)
  128. #
  129. # if not make_ok:
  130. # raise Warning('No se pudo crear la estructura de directorios')
  131. #
  132. # # 4. Create configuration file
  133. # config_ok = odoo_api.make_config_file(self.normalized_name)
  134. #
  135. # if not config_ok:
  136. # raise Warning('No se pudo crear el archivo de configuración')
  137. #
  138. # # 5. Create database
  139. # db_ok = odoo_api.create_database(self.normalized_name)
  140. #
  141. # if not db_ok:
  142. # raise Warning('No se pudo crear la base de datos')
  143. #
  144. # # 6. Copy database seed
  145. # seed_copied = odoo_api.copy_database_seed()
  146. #
  147. # if not seed_copied:
  148. # raise Warning('No se pudo copiar la estructura inicial de la base de datos')
  149. #
  150. # # 7. Restore database schema
  151. # restored = odoo_api.restore_database(self.normalized_name)
  152. #
  153. # if not restored:
  154. # raise Warning('No se pudo reestablecer la copia de base de datos')
  155. #
  156. # # 8. Remove database seed
  157. # seed_removed = odoo_api.remove_database_seed()
  158. #
  159. # if not seed_removed:
  160. # raise Warning('No se pudo remover la copia de base de datos')
  161. #
  162. # # 9. Create odoo container
  163. # odoo_created = odoo_api.create_container(self.normalized_name, [port_to_use])
  164. #
  165. # if not odoo_created:
  166. # raise Warning('No se pudo crear el contenedor')
  167. #
  168. # # 10. Apply permissions
  169. # permissions_applied = odoo_api.apply_permissions(self.normalized_name)
  170. #
  171. # if not permissions_applied:
  172. # raise Warning('No se pudo aplicar los permisos correspondientes')
  173. #
  174. # # 11. Get internal ip
  175. # internal_ip = odoo_api.get_internal_ip(self.normalized_name)
  176. #
  177. # # 12. Send email
  178. # # TODO
  179. #
  180. # print(internal_ip)
  181. #
  182. # self.state = 'activated'
  183. @api.one
  184. def action_disapprove(self):
  185. if self.state != 'draft':
  186. raise Warning('No se puede desaprobar un sistema ya activo')
  187. self.state = 'disapproved'
  188. @api.one
  189. def action_suspend(self):
  190. if self.state != 'activated':
  191. raise Warning('No se puede suspender un sistema no activo')
  192. self.state = 'suspended'
  193. self.running = False
  194. @api.one
  195. def copy(self):
  196. raise Warning('Atención', 'No se puede duplicar una instancia. Por favor, cree uno nuevo')
  197. @api.one
  198. def action_destroy(self):
  199. if self.state == 'destroyed':
  200. raise Warning('No se puede eliminar un sistema ya eliminado')
  201. self.state = 'destroyed'
  202. self.running = False
  203. @api.one
  204. def action_start(self):
  205. if self.running:
  206. raise Warning('Atención', 'No se puede arrancar una instancia que ya está arrancada')
  207. self.running = True
  208. @api.one
  209. def action_restart(self):
  210. if not self.running:
  211. raise Warning('Atención', 'No se puede parar y arrancar una instancia que ya está parada')
  212. self.running = True
  213. @api.model
  214. def check_status(self):
  215. print('croned')