Skip to content

Commit

Permalink
Merge branch '14.0-dev' into 14.0-t4055-access-levels-variables-add-f…
Browse files Browse the repository at this point in the history
…eature

Signed-off-by: Dmitry Meita <[email protected]>
  • Loading branch information
tendil authored Jan 5, 2025
2 parents c8ebc37 + de3ef9b commit 3c014db
Show file tree
Hide file tree
Showing 28 changed files with 647 additions and 92 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Available addons
----------------
addon | version | maintainers | summary
--- | --- | --- | ---
[cetmix_tower_server](cetmix_tower_server/) | 14.0.0.4.0 | | Flexible Server Management directly from Odoo
[cetmix_tower_server](cetmix_tower_server/) | 14.0.0.4.2 | | Flexible Server Management directly from Odoo
[cetmix_tower_server_notify_backend](cetmix_tower_server_notify_backend/) | 14.0.1.0.0 | | Backend notifications for Cetmix Tower
[cetmix_tower_server_queue](cetmix_tower_server_queue/) | 14.0.1.0.3 | | OCA Queue implementation for Cetmix Tower Server
[cetmix_tower_yaml](cetmix_tower_yaml/) | 14.0.1.0.0 | | Cetmix Tower YAML export/import
Expand Down
2 changes: 1 addition & 1 deletion cetmix_tower_server/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Cetmix Tower Server Management
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:4b055a9f60e7fa95ab04b470c0bf1fad7de7a7b795f211ba8d282abb73b0a212
!! source digest: sha256:46e220fd464cf2a9911e7720baa63defb7aefd08bb9c32e684b63cc00b9ddd0e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down
2 changes: 2 additions & 0 deletions cetmix_tower_server/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# pylint: disable=E8103

from . import models
from . import wizards
2 changes: 1 addition & 1 deletion cetmix_tower_server/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
"name": "Cetmix Tower Server Management",
"summary": "Flexible Server Management directly from Odoo",
"version": "14.0.0.4.0",
"version": "14.0.0.4.2",
"category": "Productivity",
"website": "https://cetmix.com",
"author": "Cetmix",
Expand Down
31 changes: 31 additions & 0 deletions cetmix_tower_server/demo/demo_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@
<record id="variable_demo_url" model="cx.tower.variable">
<field name="name">URL</field>
</record>
<record id="variable_demo_odoo_version" model="cx.tower.variable">
<field name="name">Odoo Version </field>
<field name="reference">odoo__version</field>
<field name="variable_type">o</field>
</record>
<record id="variable_demo_version" model="cx.tower.variable">
<field name="name">Version</field>
</record>
Expand Down Expand Up @@ -564,4 +569,30 @@ else:
<field name="plan_line_action_id" ref="plan_demo_1_line_2_action_1" />
<field name="value_char">final_value</field>
</record>
<!-- Variables Options -->
<record id="option_odoo_version_14" model="cx.tower.variable.option">
<field name="variable_id" ref="variable_demo_odoo_version" />
<field name="name">14.0</field>
<field name="sequence">10</field>
</record>
<record id="option_odoo_version_15" model="cx.tower.variable.option">
<field name="variable_id" ref="variable_demo_odoo_version" />
<field name="name">15.0</field>
<field name="sequence">20</field>
</record>
<record id="option_odoo_version_16" model="cx.tower.variable.option">
<field name="variable_id" ref="variable_demo_odoo_version" />
<field name="name">16.0</field>
<field name="sequence">30</field>
</record>
<record id="option_odoo_version_17" model="cx.tower.variable.option">
<field name="variable_id" ref="variable_demo_odoo_version" />
<field name="name">17.0</field>
<field name="sequence">40</field>
</record>
<record id="option_odoo_version_18" model="cx.tower.variable.option">
<field name="variable_id" ref="variable_demo_odoo_version" />
<field name="name">18.0</field>
<field name="sequence">50</field>
</record>
</odoo>
1 change: 1 addition & 0 deletions cetmix_tower_server/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
from . import cx_tower_server_log
from . import cx_tower_server_template
from . import cetmix_tower
from . import cx_tower_variable_option
27 changes: 27 additions & 0 deletions cetmix_tower_server/models/cx_tower_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ def _selection_action(self):
column1="command_id",
column2="server_id",
string="Servers",
help="Servers on which the command will be executed.\n"
"If empty, command canbe executed on all servers",
)
tag_ids = fields.Many2many(
comodel_name="cx.tower.tag",
Expand Down Expand Up @@ -133,6 +135,7 @@ def _compute_variable_ids(self):
for record in self:
record.variable_ids = record._prepare_variable_commands(["code", "path"])

# TODO: move this up
server_status = fields.Selection(
selection=lambda self: self.env["cx.tower.server"]._selection_status(),
string="Server Status",
Expand All @@ -142,6 +145,17 @@ def _compute_variable_ids(self):
),
)

# Depend on related servers and partners
@api.depends(
"code",
"server_ids",
"server_ids.partner_id",
"secret_ids.server_id",
"secret_ids.partner_id",
)
def _compute_secret_ids(self):
return super()._compute_secret_ids()

@api.depends("action")
def _compute_code(self):
"""
Expand Down Expand Up @@ -201,3 +215,16 @@ def action_open_command_logs(self):
)
action["domain"] = [("command_id", "=", self.id)]
return action

def _compose_secret_search_domain(self, key_refs):
# Check server anb partner specific secrets
return [
("reference", "in", key_refs),
"|",
"|",
("server_id", "in", self.server_ids.ids),
("partner_id", "in", self.server_ids.partner_id.ids),
"&",
("server_id", "=", False),
("partner_id", "=", False),
]
2 changes: 1 addition & 1 deletion cetmix_tower_server/models/cx_tower_file_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class CxTowerFileTemplate(models.Model):
_name = "cx.tower.file.template"
_inherit = ["cx.tower.reference.mixin"]
_inherit = ["cx.tower.reference.mixin", "cx.tower.key.mixin"]
_description = "Cx Tower File Template"

def _compute_file_count(self):
Expand Down
49 changes: 43 additions & 6 deletions cetmix_tower_server/models/cx_tower_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import re

from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.osv.expression import OR


Expand Down Expand Up @@ -47,13 +48,49 @@ class CxTowerKey(models.Model):
)
note = fields.Text()

_sql_constraints = [
(
"reference_unique",
"UNIQUE(reference, partner_id, server_id)",
"Reference must be unique",
def init(self):
"""
Remove constraint defined from the mixin
"""
self._cr.execute(
"""
DO $$
BEGIN
IF EXISTS (
SELECT 1
FROM information_schema.table_constraints
WHERE table_name = 'cx_tower_key' AND
constraint_name = 'cx_tower_key_reference_unique'
) THEN
ALTER TABLE cx_tower_key
DROP CONSTRAINT cx_tower_key_reference_unique;
END IF;
END$$;
"""
)
]

@api.constrains("reference", "partner_id", "server_id")
def _check_reference_unique(self):
"""ORM constraint to ensure uniqueness"""

# Need to check archive records as well
for rec in self.with_context(active_test=False):
if (
self.search_count(
[
("reference", "=", rec.reference),
("partner_id", "=", rec.partner_id.id),
("server_id", "=", rec.server_id.id),
]
)
> 1
):
raise ValidationError(
_(
"Reference must be unique for the combination of partner"
" and server"
)
)

def _compute_reference_code(self):
"""Compute key reference
Expand Down
17 changes: 12 additions & 5 deletions cetmix_tower_server/models/cx_tower_key_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,15 @@ def _extract_secret_ids(self, code):
if key_parts:
key_refs.append(key_parts[1])

return key_model.search(
[
("reference", "in", key_refs),
]
)
return key_model.search(self._compose_secret_search_domain(key_refs))

def _compose_secret_search_domain(self, key_refs):
"""Compose domain for searching secrets by references.
Args:
key_refs (List[str]): List of secret references.
Returns:
List: final domain for searching secrets.
"""
return [("reference", "in", key_refs)]
67 changes: 41 additions & 26 deletions cetmix_tower_server/models/cx_tower_server_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ def _create_new_server(self, name, **kwargs):
Returns:
cx.tower.server: newly created server record
"""
# Retrieving the passed variables
configuration_variables = kwargs.get("configuration_variables", {})

# We validate mandatory variables
self._validate_required_variables(configuration_variables)

servers = (
self.env["cx.tower.server"]
.with_context(skip_ssh_settings_check=True)
Expand Down Expand Up @@ -356,47 +362,56 @@ def _prepare_server_values(self, **kwargs):

def _validate_required_variables(self, configuration_variables):
"""
Validate that all required variables are present and not empty.
Validate that all required variables are present, not empty,
and that no required variable is entirely missing from the configuration.
Args:
configuration_variables (dict): A dictionary of variable references
and their values.
Raises:
ValidationError: If any required variables are missing or empty.
ValidationError: If all required variables are
missing from the configuration,
or if any required variable is empty or missing.
"""
missing_variables = []
empty_variables = []

for variable in self.variable_value_ids.filtered("required"):
variable_ref = variable.variable_reference
if variable_ref not in configuration_variables:
missing_variables.append(variable_ref)
elif not configuration_variables[variable_ref]:
empty_variables.append(variable_ref)

# Construct error message if issues are found
if missing_variables or empty_variables:
self.variable_value_ids = self.variable_value_ids
error_message = _(
"Please resolve the following issues with configuration variables:\n"
)
required_variables = self.variable_value_ids.filtered("required")
if not required_variables:
return

required_refs = [var.variable_reference for var in required_variables]
config_refs = list(configuration_variables.keys())

missing_variables = [ref for ref in required_refs if ref not in config_refs]
empty_variables = [
ref
for ref in required_refs
if ref in config_refs and not configuration_variables[ref]
]

if not (missing_variables or empty_variables):
return

if missing_variables:
error_message += _(
" - Missing variables: %(variables)s\n",
error_parts = [
_("Please resolve the following issues with configuration variables:")
]

if missing_variables:
error_parts.append(
_(
" - Missing variables: %(variables)s",
variables=", ".join(missing_variables),
)
)

if empty_variables:
error_message += _(
if empty_variables:
error_parts.append(
_(
" - Empty values for variables: %(variables)s",
variables=", ".join(empty_variables),
)
)

self.env.context = dict(self.env.context, keep_variable_state=True)

raise ValidationError(error_message)
raise ValidationError("\n".join(error_parts))

def copy(self, default=None):
"""Duplicate the server template along with variable values and server logs."""
Expand Down
12 changes: 12 additions & 0 deletions cetmix_tower_server/models/cx_tower_variable.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ class TowerVariable(models.Model):
value_ids_count = fields.Integer(
string="Value Count", compute="_compute_value_ids_count", store=True
)
option_ids = fields.One2many(
comodel_name="cx.tower.variable.option",
inverse_name="variable_id",
string="Options",
auto_join=True,
)
variable_type = fields.Selection(
selection=[("s", "String"), ("o", "Options")],
default="s",
required=True,
string="Type",
)
note = fields.Text()

_sql_constraints = [("name_uniq", "unique (name)", "Variable names must be unique")]
Expand Down
48 changes: 48 additions & 0 deletions cetmix_tower_server/models/cx_tower_variable_option.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Copyright (C) 2022 Cetmix OÜ
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).


from odoo import fields, models


class TowerVariableOption(models.Model):
"""
Model to manage variable options in the Cetmix Tower.
The model allows defining options
that are linked to tower variables and can be used to
manage configurations or settings for those variables.
Attributes:
name (str): The value of the option (e.g., "17.0").
variable_id (Many2one): A reference to the 'cx.tower.variable'
model that associates this option with a particular tower variable.
sequence (int): A sequence number to control the ordering
of the options.
SQL Constraints:
- Ensures that the combination of `name` and `variable_id`
is unique across the system.
"""

_name = "cx.tower.variable.option"
_description = "Cetmix Tower Variable Options"
_order = "sequence, name"

name = fields.Char(string="Option Value", required=True)
variable_id = fields.Many2one(
comodel_name="cx.tower.variable",
required=True,
ondelete="cascade",
)
sequence = fields.Integer(default=10)

# Define a SQL constraint to ensure the combination of
# 'name' and 'variable_id' is unique
_sql_constraints = [
(
"unique_variable_option",
"unique (name, variable_id)",
"The combination of Name and Variable must be unique.",
)
]
Loading

0 comments on commit 3c014db

Please sign in to comment.