Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions remote_server_mgmt/README.rst
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/qrtl/qrtl-custom/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 <https://github.com/qrtl/qrtl-custom/issues/new?body=module:%20remote_server_mgmt%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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 <https://github.com/qrtl/qrtl-custom/tree/16.0/remote_server_mgmt>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions remote_server_mgmt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions remote_server_mgmt/__manifest__.py
Original file line number Diff line number Diff line change
@@ -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,
}
6 changes: 6 additions & 0 deletions remote_server_mgmt/models/__init__.py
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions remote_server_mgmt/models/remote_database.py
Original file line number Diff line number Diff line change
@@ -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)"
)
59 changes: 59 additions & 0 deletions remote_server_mgmt/models/remote_server.py
Original file line number Diff line number Diff line change
@@ -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()
19 changes: 19 additions & 0 deletions remote_server_mgmt/models/remote_server_tag.py
Original file line number Diff line number Diff line change
@@ -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())
36 changes: 36 additions & 0 deletions remote_server_mgmt/models/remote_url.py
Original file line number Diff line number Diff line change
@@ -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
)
)
40 changes: 40 additions & 0 deletions remote_server_mgmt/models/server_command_properties.py
Original file line number Diff line number Diff line change
@@ -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()
13 changes: 13 additions & 0 deletions remote_server_mgmt/models/server_static_properties.py
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions remote_server_mgmt/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This module simplifies the management of customer server properties.
4 changes: 4 additions & 0 deletions remote_server_mgmt/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 10 additions & 0 deletions remote_server_mgmt/security/ir.model.access.csv
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions remote_server_mgmt/security/remote_server_mgmt_security.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.module.category" id="module_category">
<field name="name">Remote Servers</field>
</record>
<record id="group_remote_server_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="module_category" />
<field name="implied_ids" eval="[Command.link(ref('base.group_user'))]" />
</record>
<record id="group_remote_server_officer" model="res.groups">
<field name="name">Officer</field>
<field name="category_id" ref="module_category" />
<field
name="implied_ids"
eval="[Command.link(ref('group_remote_server_user'))]"
/>
</record>
<record id="group_remote_server_manager" model="res.groups">
<field name="name">Administrator</field>
<field name="category_id" ref="module_category" />
<field
name="implied_ids"
eval="[Command.link(ref('group_remote_server_officer'))]"
/>
<field
name="users"
eval="[Command.link(ref('base.user_root')), Command.link(ref('base.user_admin'))]"
/>
</record>
</odoo>
Loading
Loading