diff --git a/remote_server_mgmt/README.rst b/remote_server_mgmt/README.rst new file mode 100644 index 0000000..53a7829 --- /dev/null +++ b/remote_server_mgmt/README.rst @@ -0,0 +1,63 @@ +========================= +Remote Servers Management +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d8a94a3f0b50cc73827f85f30a2e1288fc51202423f336a217910a651141b2b5 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-qrtl%2Fqrtl--custom-lightgray.png?logo=github + :target: https://github.com/qrtl/qrtl-custom/tree/16.0/remote_server_mgmt + :alt: qrtl/qrtl-custom + +|badge1| |badge2| |badge3| + +This module simplifies the management of customer server properties. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To manage your customer's server, open the Server Management app. Add a +new remote server and fill in its details. If you need to sync the +server command properties, just click the 'SYNC COMMAND PROPERTIES' +button at the top. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Quartile + +Maintainers +----------- + +This module is part of the `qrtl/qrtl-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/remote_server_mgmt/__init__.py b/remote_server_mgmt/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/remote_server_mgmt/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/remote_server_mgmt/__manifest__.py b/remote_server_mgmt/__manifest__.py new file mode 100644 index 0000000..b853974 --- /dev/null +++ b/remote_server_mgmt/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). +{ + "name": "Remote Servers Management", + "version": "16.0.1.0.0", + "category": "Others", + "author": "Quartile", + "website": "https://www.quartile.co", + "license": "LGPL-3", + "external_dependencies": {"python": ["paramiko"]}, + "depends": ["mail"], + "data": [ + "security/remote_server_mgmt_security.xml", + "security/ir.model.access.csv", + "views/remote_server_mgmt_menu.xml", + "views/remote_server_tag_views.xml", + "views/remote_server_views.xml", + ], + "installable": True, +} diff --git a/remote_server_mgmt/models/__init__.py b/remote_server_mgmt/models/__init__.py new file mode 100644 index 0000000..c7a9ee1 --- /dev/null +++ b/remote_server_mgmt/models/__init__.py @@ -0,0 +1,6 @@ +from . import remote_database +from . import remote_server +from . import remote_server_tag +from . import remote_url +from . import server_command_properties +from . import server_static_properties diff --git a/remote_server_mgmt/models/remote_database.py b/remote_server_mgmt/models/remote_database.py new file mode 100644 index 0000000..1b366b1 --- /dev/null +++ b/remote_server_mgmt/models/remote_database.py @@ -0,0 +1,15 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class RemoteDatabase(models.Model): + _name = "remote.database" + _description = "Remote Database" + + name = fields.Char("Database Name", required=True) + remote_server_id = fields.Many2one("remote.server", "Server") + server_url_ids = fields.One2many( + "remote.url", "remote_database_id", string="URL(s)" + ) diff --git a/remote_server_mgmt/models/remote_server.py b/remote_server_mgmt/models/remote_server.py new file mode 100644 index 0000000..3dd0c30 --- /dev/null +++ b/remote_server_mgmt/models/remote_server.py @@ -0,0 +1,59 @@ +# Copyright 2020-2025 Quartile +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class RemoteServer(models.Model): + _name = "remote.server" + _inherit = ["mail.thread", "mail.activity.mixin"] + _description = "Remote Server" + + name = fields.Char("Description/Usage", required=True) + partner_id = fields.Many2one("res.partner") + server_ip = fields.Char("IP") + ssh_user = fields.Char("SSH User") + ssh_port = fields.Integer("SSH Port") + private_key_path = fields.Char() + active = fields.Boolean(default=True) + server_command_properties_ids = fields.One2many( + "server.command.properties", + "remote_server_id", + string="Command Properties", + ) + server_static_properties_ids = fields.One2many( + "server.static.properties", "remote_server_id", string="Static Properties" + ) + server_url_ids = fields.One2many( + "remote.url", "remote_server_id", string="Access URL(s)" + ) + database_ids = fields.One2many( + "remote.database", "remote_server_id", string="Odoo Database(s)" + ) + odoo_version = fields.Char(required=True) + # managed_by_qrtl = fields.Boolean(default=True) + tag_ids = fields.Many2many("remote.server.tag", string="Tags") + service_provider = fields.Char() + storage_size = fields.Integer("Storage(GB)") + vcore = fields.Float("vCore") + ram_size = fields.Integer("RAM(GB)") + tsl_provider = fields.Char("TSL Provider") + web_server = fields.Char() + os = fields.Char("OS") + backup_location = fields.Char() + remark = fields.Text() + + def action_read_remote_server(self): + self.ensure_one() + return { + "name": self.display_name, + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "form", + "res_model": "remote.server", + "res_id": self.id, + } + + def sync_command_properties(self): + for prop in self.server_command_properties_ids: + prop._compute_property_value() diff --git a/remote_server_mgmt/models/remote_server_tag.py b/remote_server_mgmt/models/remote_server_tag.py new file mode 100644 index 0000000..498b1a9 --- /dev/null +++ b/remote_server_mgmt/models/remote_server_tag.py @@ -0,0 +1,19 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from random import randint + +from odoo import fields, models + + +class RemoteServerTag(models.Model): + _name = "remote.server.tag" + _description = "Remote Server Tag" + _order = "sequence, id" + + def _default_color(self): + return randint(1, 11) + + name = fields.Char("Name", required=True, translate=True) + sequence = fields.Integer("Sequence", default=0) + color = fields.Integer("Color Index", default=lambda self: self._default_color()) diff --git a/remote_server_mgmt/models/remote_url.py b/remote_server_mgmt/models/remote_url.py new file mode 100644 index 0000000..43be611 --- /dev/null +++ b/remote_server_mgmt/models/remote_url.py @@ -0,0 +1,36 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +import logging +from urllib.request import urlopen + +from odoo import api, fields, models + +_logger = logging.getLogger(__name__) + + +class RemoteUrl(models.Model): + _name = "remote.url" + _description = "Remote URL" + + name = fields.Char("Domain", required=True) + remote_server_id = fields.Many2one("remote.server", "Server") + remote_database_id = fields.Many2one("remote.database", "Database") + valid = fields.Boolean("URL Valid", compute="_compute_valid") + + @api.depends("name") + def _compute_valid(self): + for url in self: + url.valid = False + if not url.name: + continue + try: + response = urlopen(f"http://{url.name}", timeout=10) + # Assuming that we want to store any 2xx status as a valid URL + url.valid = 200 <= response.getcode() < 300 + except Exception as e: + _logger.error( + "An error occurred while validating URL '{}': {}".format( + url.name, e + ) + ) diff --git a/remote_server_mgmt/models/server_command_properties.py b/remote_server_mgmt/models/server_command_properties.py new file mode 100644 index 0000000..ad1999e --- /dev/null +++ b/remote_server_mgmt/models/server_command_properties.py @@ -0,0 +1,40 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +import paramiko + +from odoo import _, api, fields, models +from odoo.exceptions import UserError + + +class ServerCommandProperties(models.Model): + _name = "server.command.properties" + _description = "Server Command Properties" + + name = fields.Char("Property", required=True) + remote_server_id = fields.Many2one("remote.server", "Server") + command = fields.Char(required=True) + property_value = fields.Text("Value", compute="_compute_property_value", store=True) + + @api.depends("command") + def _compute_property_value(self): + for prop in self: + if prop.command and prop.remote_server_id: + ssh = paramiko.SSHClient() + try: + key = paramiko.RSAKey.from_private_key_file( + prop.remote_server_id.private_key_path + ) + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect( + prop.remote_server_id.server_ip, + port=prop.remote_server_id.ssh_port, + username=prop.remote_server_id.ssh_user, + pkey=key, + ) + _stdin, stdout, _stderr = ssh.exec_command(prop.command) + prop.property_value = stdout.read().decode("ascii").strip("\n") + except (paramiko.SSHException, FileNotFoundError) as e: + raise UserError(_("An error occurred: {}".format(e))) from e + finally: + ssh.close() diff --git a/remote_server_mgmt/models/server_static_properties.py b/remote_server_mgmt/models/server_static_properties.py new file mode 100644 index 0000000..c30c93b --- /dev/null +++ b/remote_server_mgmt/models/server_static_properties.py @@ -0,0 +1,13 @@ +# Copyright 2020-2025 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class ServerStaticProperties(models.Model): + _name = "server.static.properties" + _description = "Server Static Properties" + + name = fields.Char("Property", required=True) + remote_server_id = fields.Many2one("remote.server", "Server") + property_value = fields.Text("Value", required=True) diff --git a/remote_server_mgmt/readme/DESCRIPTION.md b/remote_server_mgmt/readme/DESCRIPTION.md new file mode 100644 index 0000000..779e99c --- /dev/null +++ b/remote_server_mgmt/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module simplifies the management of customer server properties. diff --git a/remote_server_mgmt/readme/USAGE.md b/remote_server_mgmt/readme/USAGE.md new file mode 100644 index 0000000..b0b7778 --- /dev/null +++ b/remote_server_mgmt/readme/USAGE.md @@ -0,0 +1,4 @@ +To manage your customer's server, open the Server Management app. Add a +new remote server and fill in its details. If you need to sync the +server command properties, just click the 'SYNC COMMAND PROPERTIES' +button at the top. diff --git a/remote_server_mgmt/security/ir.model.access.csv b/remote_server_mgmt/security/ir.model.access.csv new file mode 100644 index 0000000..64a1ac5 --- /dev/null +++ b/remote_server_mgmt/security/ir.model.access.csv @@ -0,0 +1,10 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_remote_database,access_remote_database,model_remote_database,base.group_user,1,1,1,0 +access_remote_server_user,remote.server.user,model_remote_server,remote_server_mgmt.group_remote_server_user,1,0,0,0 +access_remote_server_officer,remote.server.officer,model_remote_server,remote_server_mgmt.group_remote_server_officer,1,1,1,0 +access_remote_server_manager,remote.server.manager,model_remote_server,remote_server_mgmt.group_remote_server_manager,1,1,1,1 +access_remote_server_tag_user,remote.server.tag.user,model_remote_server_tag,base.group_user,1,0,0,0 +access_remote_server_tag_manager,remote.server.tag.manager,model_remote_server_tag,remote_server_mgmt.group_remote_server_manager,1,1,1,1 +access_remote_url,access_remote_url,model_remote_url,base.group_user,1,1,1,0 +access_server_command_properties,access_server_command_properties,model_server_command_properties,base.group_user,1,1,1,0 +access_server_static_properties,access_server_static_properties,model_server_static_properties,base.group_user,1,1,1,0 diff --git a/remote_server_mgmt/security/remote_server_mgmt_security.xml b/remote_server_mgmt/security/remote_server_mgmt_security.xml new file mode 100644 index 0000000..b7753d1 --- /dev/null +++ b/remote_server_mgmt/security/remote_server_mgmt_security.xml @@ -0,0 +1,31 @@ + + + + Remote Servers + + + User + + + + + Officer + + + + + Administrator + + + + + diff --git a/remote_server_mgmt/static/description/index.html b/remote_server_mgmt/static/description/index.html new file mode 100644 index 0000000..92110d7 --- /dev/null +++ b/remote_server_mgmt/static/description/index.html @@ -0,0 +1,416 @@ + + + + + +Remote Servers Management + + + +
+

Remote Servers Management

+ + +

Beta License: LGPL-3 qrtl/qrtl-custom

+

This module simplifies the management of customer server properties.

+

Table of contents

+ +
+

Usage

+

To manage your customer’s server, open the Server Management app. Add a +new remote server and fill in its details. If you need to sync the +server command properties, just click the ‘SYNC COMMAND PROPERTIES’ +button at the top.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile
  • +
+
+
+

Maintainers

+

This module is part of the qrtl/qrtl-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/remote_server_mgmt/views/remote_server_mgmt_menu.xml b/remote_server_mgmt/views/remote_server_mgmt_menu.xml new file mode 100644 index 0000000..136441d --- /dev/null +++ b/remote_server_mgmt/views/remote_server_mgmt_menu.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/remote_server_mgmt/views/remote_server_tag_views.xml b/remote_server_mgmt/views/remote_server_tag_views.xml new file mode 100644 index 0000000..738f9f8 --- /dev/null +++ b/remote_server_mgmt/views/remote_server_tag_views.xml @@ -0,0 +1,26 @@ + + + + remote.server.tag.view.tree + remote.server.tag + + + + + + + + + + Remote Server Tags + remote.server.tag + tree + + + diff --git a/remote_server_mgmt/views/remote_server_views.xml b/remote_server_mgmt/views/remote_server_views.xml new file mode 100644 index 0000000..3252b3f --- /dev/null +++ b/remote_server_mgmt/views/remote_server_views.xml @@ -0,0 +1,173 @@ + + + + remote.server.search + remote.server + + + + + + + + + + + + + + + + + + + + + + + remote.server.tree + remote.server + + + + +