Tower: upload cetmix_tower_server 16.0.3.0.1 (via marketplace)
This commit is contained in:
@@ -0,0 +1,474 @@
|
||||
import logging
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CxTowerJetTemplateInstall(models.Model):
|
||||
"""
|
||||
Used to track installation of Jet Templates on servers.
|
||||
"""
|
||||
|
||||
_name = "cx.tower.jet.template.install"
|
||||
_description = "Jet Template Install/Uninstall"
|
||||
_order = "create_date desc"
|
||||
_rec_name = "jet_template_id"
|
||||
|
||||
jet_template_id = fields.Many2one(
|
||||
comodel_name="cx.tower.jet.template",
|
||||
required=True,
|
||||
help="Template to install/uninstall",
|
||||
)
|
||||
server_id = fields.Many2one(
|
||||
comodel_name="cx.tower.server",
|
||||
index=True,
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
help="Server to install/uninstall the template on",
|
||||
)
|
||||
action = fields.Selection(
|
||||
selection=[("install", "Install"), ("uninstall", "Uninstall")],
|
||||
default="install",
|
||||
)
|
||||
date_done = fields.Datetime(string="Completed on", readonly=True)
|
||||
line_ids = fields.One2many(
|
||||
comodel_name="cx.tower.jet.template.install.line",
|
||||
inverse_name="jet_template_install_id",
|
||||
auto_join=True,
|
||||
string="Templates to install",
|
||||
help="Complete list of templates to install/uninstall including dependencies",
|
||||
)
|
||||
current_line_id = fields.Many2one(
|
||||
comodel_name="cx.tower.jet.template.install.line",
|
||||
string="Currently Installing",
|
||||
help="Line that is currently being installed",
|
||||
)
|
||||
state = fields.Selection(
|
||||
selection=[
|
||||
("processing", "Processing"),
|
||||
("done", "Done"),
|
||||
("failed", "Failed"),
|
||||
],
|
||||
default="processing",
|
||||
index=True,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def install(self, server, template):
|
||||
"""Install the template on the server.
|
||||
|
||||
Args:
|
||||
server (cx.tower.server()): The server to install the template on.
|
||||
template (cx.tower.jet.template()): The template to install.
|
||||
|
||||
Returns:
|
||||
cx.tower.jet.template.install(): The installation record.
|
||||
"""
|
||||
server.ensure_one()
|
||||
template.ensure_one()
|
||||
|
||||
# Compose the list of templates to install
|
||||
# NB: templates will be installed later in reverse order
|
||||
# to ensure that dependencies are satisfied
|
||||
template_to_process = [template] + template._check_dependency_satisfaction(
|
||||
server
|
||||
)
|
||||
|
||||
# Prepare the template install lines
|
||||
template_to_process_lines = []
|
||||
order = 0
|
||||
for t in template_to_process:
|
||||
template_to_process_lines.append(
|
||||
(0, 0, {"jet_template_id": t.id, "order": order})
|
||||
)
|
||||
order += 1
|
||||
|
||||
# Create a new install record
|
||||
install_record = self.create(
|
||||
{
|
||||
"jet_template_id": template.id,
|
||||
"server_id": server.id,
|
||||
"line_ids": template_to_process_lines,
|
||||
}
|
||||
)
|
||||
|
||||
# Send notification
|
||||
# Action for button
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"cetmix_tower_server.cx_tower_jet_template_install_action"
|
||||
)
|
||||
|
||||
context = self.env.context.copy()
|
||||
params = dict(context.get("params") or {})
|
||||
params["button_name"] = _("View Installation")
|
||||
context["params"] = params
|
||||
|
||||
# Add record id and context to the action
|
||||
action.update(
|
||||
{
|
||||
"context": context,
|
||||
"res_id": install_record.id,
|
||||
"views": [(False, "form")],
|
||||
}
|
||||
)
|
||||
|
||||
self.env.user.notify_info(
|
||||
message=_(
|
||||
"%(timestamp)s<br/>" "Installing template on server '%(server_name)s'",
|
||||
server_name=server.name,
|
||||
timestamp=fields.Datetime.context_timestamp(
|
||||
self, fields.Datetime.now()
|
||||
),
|
||||
),
|
||||
title=template.name,
|
||||
sticky=False, # explicitly set to False to avoid blocking the user's screen
|
||||
action=action,
|
||||
)
|
||||
|
||||
# Launch the installation
|
||||
install_record._process_install()
|
||||
|
||||
# Return the installation record
|
||||
return install_record
|
||||
|
||||
@api.model
|
||||
def uninstall(self, server, template):
|
||||
"""Uninstall the template from the server.
|
||||
NB: only one template can be uninstalled at a time.
|
||||
|
||||
Args:
|
||||
server (cx.tower.server()): The server to uninstall the template from.
|
||||
template (cx.tower.jet.template()): The template to uninstall.
|
||||
"""
|
||||
server.ensure_one()
|
||||
template.ensure_one()
|
||||
|
||||
# Create a new install record
|
||||
install_record = self.create(
|
||||
{
|
||||
"jet_template_id": template.id,
|
||||
"server_id": server.id,
|
||||
"line_ids": [(0, 0, {"jet_template_id": template.id, "order": 0})],
|
||||
"action": "uninstall",
|
||||
}
|
||||
)
|
||||
|
||||
# Send notification
|
||||
# Action for button
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"cetmix_tower_server.cx_tower_jet_template_install_action"
|
||||
)
|
||||
|
||||
context = self.env.context.copy()
|
||||
params = dict(context.get("params") or {})
|
||||
params["button_name"] = _("View Installation")
|
||||
context["params"] = params
|
||||
|
||||
# Add record id and context to the action
|
||||
action.update(
|
||||
{
|
||||
"context": context,
|
||||
"res_id": install_record.id,
|
||||
"views": [(False, "form")],
|
||||
}
|
||||
)
|
||||
|
||||
self.env.user.notify_info(
|
||||
message=_(
|
||||
"%(timestamp)s<br/>"
|
||||
"Uninstalling template on server '%(server_name)s'",
|
||||
server_name=server.name,
|
||||
timestamp=fields.Datetime.context_timestamp(
|
||||
self, fields.Datetime.now()
|
||||
),
|
||||
),
|
||||
title=template.name,
|
||||
sticky=False, # explicitly set to False to avoid blocking the user's screen
|
||||
action=action,
|
||||
)
|
||||
|
||||
# Launch the installation
|
||||
install_record._process_install()
|
||||
|
||||
# Return the installation record
|
||||
return install_record
|
||||
|
||||
def _process_install(self):
|
||||
"""
|
||||
Process the installation or uninstallation of the template.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# We are not using `while` because flight plans
|
||||
# may run asynchronously and we don't want to
|
||||
# block the execution of the function
|
||||
|
||||
# Continue only if the job is still processing
|
||||
if self.state != "processing":
|
||||
return
|
||||
|
||||
# Exit if there are some lines currently being installed
|
||||
if self.current_line_id:
|
||||
return
|
||||
|
||||
# Get the template to install
|
||||
installation_tasks = self.line_ids.sorted("order", reverse=True)
|
||||
for installation_task in installation_tasks:
|
||||
# Pick the templates only in the "To Process" state
|
||||
if installation_task.state != "to_process":
|
||||
continue
|
||||
|
||||
# Get the flight plan to install the template
|
||||
if self.action == "install":
|
||||
flight_plan = installation_task.jet_template_id.plan_install_id # pylint: disable=no-member
|
||||
else:
|
||||
flight_plan = installation_task.jet_template_id.plan_uninstall_id # pylint: disable=no-member
|
||||
|
||||
# Run the corresponding flight plan
|
||||
if flight_plan:
|
||||
# Update the current template install line
|
||||
self.write(
|
||||
{
|
||||
"current_line_id": installation_task.id,
|
||||
}
|
||||
)
|
||||
|
||||
# Add the install record to the flight plan params
|
||||
plan_params = {
|
||||
"jet_template_install_id": self.id, # pylint: disable=no-member
|
||||
}
|
||||
with self.env.cr.savepoint():
|
||||
# Run the flight plan (exceptions handled inside the flight plan)
|
||||
self.server_id.run_flight_plan(
|
||||
flight_plan=flight_plan,
|
||||
jet_template=installation_task.jet_template_id,
|
||||
**{"plan_log": plan_params},
|
||||
)
|
||||
# Flight plan will trigger the `_process_install` function again
|
||||
# if the flight plan is finished successfully.
|
||||
# So we don't need continue the loop in this case.
|
||||
return
|
||||
|
||||
# Mark the installation task as "Done"
|
||||
# because nothing else is to be done here.
|
||||
installation_task.write(
|
||||
{
|
||||
"state": "done",
|
||||
}
|
||||
)
|
||||
# Add to the list of installed templates
|
||||
if self.action == "install":
|
||||
installation_task.jet_template_id.write(
|
||||
{"server_ids": [(4, self.server_id.id)]}
|
||||
)
|
||||
else:
|
||||
installation_task.jet_template_id.write(
|
||||
{"server_ids": [(3, self.server_id.id)]}
|
||||
)
|
||||
|
||||
# Refresh the frontend views
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.jet.template.install",
|
||||
rec_ids=[self.id],
|
||||
)
|
||||
|
||||
# Mark the installation as done
|
||||
now = fields.Datetime.now()
|
||||
self.write(
|
||||
{
|
||||
"state": "done",
|
||||
"date_done": now,
|
||||
}
|
||||
)
|
||||
|
||||
# Refresh the frontend views
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.jet.template.install", rec_ids=[self.id]
|
||||
)
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.server", view_types=["form"], rec_ids=[self.server_id.id]
|
||||
)
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.jet.template",
|
||||
view_types=["form"],
|
||||
rec_ids=[self.jet_template_id.id],
|
||||
)
|
||||
|
||||
# Check if notifications are enabled
|
||||
ICP_sudo = self.env["ir.config_parameter"].sudo()
|
||||
notification_type_success = ICP_sudo.get_param(
|
||||
"cetmix_tower_server.notification_type_success"
|
||||
)
|
||||
# Send notification to the user
|
||||
if notification_type_success:
|
||||
# Action for button
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"cetmix_tower_server.cx_tower_jet_template_install_action"
|
||||
)
|
||||
|
||||
context = self.env.context.copy()
|
||||
params = dict(context.get("params") or {})
|
||||
params["button_name"] = _("View Installation")
|
||||
context["params"] = params
|
||||
|
||||
# Add record id and context to the action
|
||||
action.update(
|
||||
{
|
||||
"context": context,
|
||||
"res_id": self.id,
|
||||
"views": [(False, "form")],
|
||||
}
|
||||
)
|
||||
# Send success notification
|
||||
self.env.user.notify_success(
|
||||
message=_(
|
||||
"%(timestamp)s<br/>"
|
||||
"%(action)s completed on server '%(server_name)s'",
|
||||
action=_("Installation")
|
||||
if self.action == "install"
|
||||
else _("Uninstallation"),
|
||||
server_name=self.server_id.name,
|
||||
timestamp=fields.Datetime.context_timestamp(self, now),
|
||||
),
|
||||
title=self.jet_template_id.name, # pylint: disable=no-member
|
||||
sticky=notification_type_success == "sticky",
|
||||
action=action,
|
||||
)
|
||||
|
||||
def _flight_plan_finished(self, plan_status):
|
||||
"""
|
||||
Triggered when a flight plan that is used for installing/uninstalling
|
||||
a template is finished.
|
||||
|
||||
Args:
|
||||
plan_status (int): The exit code of the flight plan.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# Validate callback state
|
||||
if not self.current_line_id:
|
||||
_logger.warning(
|
||||
"Callback invoked with no current_line_id for install %s", self.id
|
||||
)
|
||||
return
|
||||
|
||||
if self.state != "processing":
|
||||
_logger.warning(
|
||||
"Callback invoked for install %s in state %s", self.id, self.state
|
||||
)
|
||||
return
|
||||
|
||||
# Flight plan finished successfully
|
||||
if plan_status == 0:
|
||||
# Mark current line as done
|
||||
self.current_line_id.write( # pylint: disable=no-member
|
||||
{
|
||||
"state": "done",
|
||||
}
|
||||
)
|
||||
# Add template to the list of installed templates
|
||||
# or remove it from the list if it is being uninstalled
|
||||
if self.action == "install":
|
||||
self.current_line_id.jet_template_id.write( # pylint: disable=no-member
|
||||
{"server_ids": [(4, self.server_id.id)]}
|
||||
)
|
||||
else:
|
||||
self.current_line_id.jet_template_id.write( # pylint: disable=no-member
|
||||
{"server_ids": [(3, self.server_id.id)]}
|
||||
)
|
||||
|
||||
# Remove the link to the current line and continue
|
||||
self.write({"current_line_id": False})
|
||||
|
||||
# Refresh the frontend views
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.jet.template.install",
|
||||
rec_ids=[self.id],
|
||||
)
|
||||
self._process_install()
|
||||
else:
|
||||
# Mark current line as failed
|
||||
self.current_line_id.write( # pylint: disable=no-member
|
||||
{
|
||||
"state": "failed",
|
||||
}
|
||||
)
|
||||
# Clear the current line link
|
||||
self.write(
|
||||
{
|
||||
"state": "failed",
|
||||
"date_done": fields.Datetime.now(),
|
||||
"current_line_id": False,
|
||||
}
|
||||
)
|
||||
|
||||
# Set all other 'to_process' lines as failed
|
||||
self.line_ids.filtered(lambda line: line.state == "to_process").write(
|
||||
{
|
||||
"state": "failed",
|
||||
}
|
||||
)
|
||||
|
||||
# Refresh the frontend views
|
||||
self.env.user.reload_views(
|
||||
model="cx.tower.jet.template.install",
|
||||
rec_ids=[self.id],
|
||||
)
|
||||
# Send notification to the user
|
||||
# Check if notifications are enabled
|
||||
ICP_sudo = self.env["ir.config_parameter"].sudo()
|
||||
notification_type_error = ICP_sudo.get_param(
|
||||
"cetmix_tower_server.notification_type_error"
|
||||
)
|
||||
if notification_type_error:
|
||||
# Action for button
|
||||
action = self.env["ir.actions.act_window"]._for_xml_id(
|
||||
"cetmix_tower_server.cx_tower_jet_template_install_action"
|
||||
)
|
||||
|
||||
context = self.env.context.copy()
|
||||
params = dict(context.get("params") or {})
|
||||
params["button_name"] = _("View Installation")
|
||||
context["params"] = params
|
||||
|
||||
# Add record id and context to the action
|
||||
action.update(
|
||||
{
|
||||
"context": context,
|
||||
"res_id": self.id,
|
||||
"views": [(False, "form")],
|
||||
}
|
||||
)
|
||||
# Send error notification
|
||||
self.env.user.notify_danger(
|
||||
message=_(
|
||||
"%(timestamp)s<br/>"
|
||||
"%(action)s failed on server '%(server_name)s'",
|
||||
action=_("Installation")
|
||||
if self.action == "install"
|
||||
else _("Uninstallation"),
|
||||
server_name=self.server_id.name,
|
||||
timestamp=fields.Datetime.context_timestamp(
|
||||
self, fields.Datetime.now()
|
||||
),
|
||||
),
|
||||
title=self.jet_template_id.name,
|
||||
sticky=notification_type_error == "sticky",
|
||||
action=action,
|
||||
)
|
||||
|
||||
def action_view_flight_plan_logs(self):
|
||||
"""Open flight plan logs related to this installation"""
|
||||
self.ensure_one()
|
||||
|
||||
return {
|
||||
"name": _(
|
||||
"Flight Plan Logs - %(install_name)s",
|
||||
install_name=self.jet_template_id.name,
|
||||
),
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "cx.tower.plan.log",
|
||||
"view_mode": "tree,form",
|
||||
"domain": [("jet_template_install_id", "=", self.id)], # pylint: disable=no-member
|
||||
}
|
||||
Reference in New Issue
Block a user