Fill VSP server field with Proxmox VM CT ID data

This commit is contained in:
Mario
2024-08-04 22:26:24 +02:00
parent 62b516bf25
commit 1da7870720
5 changed files with 200 additions and 29 deletions

View File

@@ -9,7 +9,11 @@
""",
'author': 'Your Company',
'website': 'https://www.yourcompany.com',
'depends': ['base', 'portal'],
'depends': [
'base',
'portal',
'mail',
],
'data': [
'security/ir.model.access.csv',
'views/vps_server_views.xml',

View File

@@ -1,19 +1,159 @@
from odoo import models, fields, api
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import requests
import urllib3
import ipaddress
class VPSServer(models.Model):
_name = 'vps.server'
_description = 'VPS Server'
_inherit = ['portal.mixin', 'mail.thread', 'mail.activity.mixin']
name = fields.Char(string='Server Name', required=True)
ip_address = fields.Char(string='IP Address', required=True)
cpu = fields.Integer(string='CPU Cores')
ram = fields.Float(string='RAM (GB)')
storage = fields.Float(string='Storage (GB)')
os = fields.Char(string='Operating System')
customer_id = fields.Many2one('res.partner', string='Customer', required=True)
name = fields.Char(string='Server Name', required=True, tracking=True)
ipv4_address = fields.Text(string='IPv4 Addresses', tracking=True)
ipv6_address = fields.Text(string='IPv6 Addresses', tracking=True)
cpu = fields.Integer(string='CPU Cores', tracking=True)
ram = fields.Float(string='RAM (GB)', tracking=True)
storage = fields.Float(string='Storage (GB)', tracking=True)
os = fields.Char(string='Operating System', tracking=True)
customer_id = fields.Many2one('res.partner', string='Customer', required=True, tracking=True)
proxmox_server_id = fields.Many2one('proxmox.server', string='Proxmox Server', tracking=True)
ct_id = fields.Integer(string='CT ID (LXC)', tracking=True)
vm_id = fields.Integer(string='VM ID (QEMU)', tracking=True)
def _compute_access_url(self):
super()._compute_access_url()
for server in self:
server.access_url = '/my/vps-servers/%s' % server.id
@api.onchange('ct_id', 'vm_id')
def _onchange_id(self):
if self.ct_id and self.vm_id:
raise UserError(_("Please provide either CT ID or VM ID, not both."))
def action_fetch_proxmox_data(self):
self.ensure_one()
if not self.proxmox_server_id:
raise UserError(_("Please select a Proxmox server first."))
if not self.ct_id and not self.vm_id:
raise UserError(_("Please provide either CT ID or VM ID."))
proxmox = self.proxmox_server_id
base_url = proxmox.url.rstrip('/')
headers = {
"Authorization": f"PVEAPIToken={proxmox.api_token_id}={proxmox.api_token_secret}"
}
try:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Determine if it's a container or VM
if self.ct_id:
vm_type = 'lxc'
vm_id = self.ct_id
else:
vm_type = 'qemu'
vm_id = self.vm_id
# Fetch VM/CT status
status_response = requests.get(
f"{base_url}/api2/json/nodes/pve/{vm_type}/{vm_id}/status/current",
verify=False,
headers=headers
)
status_response.raise_for_status()
status_data = status_response.json()['data']
# Fetch VM/CT config
config_response = requests.get(
f"{base_url}/api2/json/nodes/pve/{vm_type}/{vm_id}/config",
verify=False,
headers=headers
)
config_response.raise_for_status()
config_data = config_response.json()['data']
# Update fields
self.name = config_data.get('name', f"{vm_type}-{vm_id}")
self.cpu = status_data.get('cpus', 0)
self.ram = status_data.get('maxmem', 0) / (1024 * 1024 * 1024) # Convert to GB
self.storage = status_data.get('maxdisk', 0) / (1024 * 1024 * 1024) # Convert to GB
# Try to get IP addresses
ipv4_addresses = []
ipv6_addresses = []
def parse_ip(ip):
try:
ip_obj = ipaddress.ip_address(ip.split('/')[0])
return str(ip_obj), 'v4' if ip_obj.version == 4 else 'v6'
except ValueError:
return None, None
if vm_type == 'lxc':
for key, value in config_data.items():
if key.startswith('net'):
ip_configs = value.split(',')
for config in ip_configs:
if config.startswith('ip=') or config.startswith('ip6='):
ip = config.split('=')[1]
parsed_ip, ip_type = parse_ip(ip)
if parsed_ip:
if ip_type == 'v4':
ipv4_addresses.append(parsed_ip)
else:
ipv6_addresses.append(parsed_ip)
else: # QEMU
for key, value in config_data.items():
if key.startswith('ipconfig'):
ips = value.split(',')
for ip_config in ips:
if '=' in ip_config:
ip = ip_config.split('=')[1]
parsed_ip, ip_type = parse_ip(ip)
if parsed_ip:
if ip_type == 'v4':
ipv4_addresses.append(parsed_ip)
else:
ipv6_addresses.append(parsed_ip)
self.ipv4_address = ', '.join(ipv4_addresses) if ipv4_addresses else 'No IPv4 found'
self.ipv6_address = ', '.join(ipv6_addresses) if ipv6_addresses else 'No IPv6 found'
# Try to get OS info
if vm_type == 'lxc':
self.os = config_data.get('ostype', 'Unknown')
else: # QEMU
self.os = config_data.get('ostype', 'Unknown')
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('Data Fetched'),
'message': _('Successfully fetched data from Proxmox server.'),
'sticky': False,
'type': 'success',
}
}
except requests.exceptions.RequestException as e:
raise UserError(_("Failed to fetch data from Proxmox server: %s") % str(e))
@api.model
def create(self, vals):
record = super(VPSServer, self).create(vals)
record.message_subscribe(partner_ids=[record.customer_id.id])
return record
def write(self, vals):
res = super(VPSServer, self).write(vals)
if 'customer_id' in vals:
self.message_subscribe(partner_ids=[vals['customer_id']])
return res
def unlink(self):
for record in self:
record.message_unsubscribe(partner_ids=[record.customer_id.id])
return super(VPSServer, self).unlink()

View File

@@ -4,15 +4,15 @@
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">VPS Servers</t>
<t t-set="url" t-value="'/my/vps-servers'" />
<t t-set="placeholder_count" t-value="'vps_server_count'" />
<t t-set="url" t-value="'/my/vps-servers'"/>
<t t-set="placeholder_count" t-value="'vps_server_count'"/>
</t>
</xpath>
</template>
<template id="portal_my_vps_servers" name="My VPS Servers">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True" />
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<t t-set="title">VPS Servers</t>
</t>
@@ -20,9 +20,10 @@
<thead>
<tr class="active">
<th>Server Name</th>
<th class='d-none d-md-table-cell'>IP Address</th>
<th class='d-none d-md-table-cell'>CPU</th>
<th class='text-right'>RAM</th>
<th class='d-none d-md-table-cell'>IPv4 Address</th>
<th class='d-none d-md-table-cell'>IPv6 Address</th>
<th class='text-right'>CPU</th>
<th class='text-right'>RAM (GB)</th>
</tr>
</thead>
<tbody>
@@ -32,17 +33,20 @@
<a t-att-href="server.get_portal_url()"
t-attf-class="tr_vps_server_link"
t-att-title="server.name">
<t t-esc="server.name" />
<t t-esc="server.name"/>
</a>
</td>
<td class="d-none d-md-table-cell">
<span t-field="server.ip_address" />
<span t-field="server.ipv4_address"/>
</td>
<td class="d-none d-md-table-cell">
<span t-field="server.cpu" />
<span t-field="server.ipv6_address"/>
</td>
<td class='text-right'>
<span t-field="server.ram" />
<span t-field="server.cpu"/>
</td>
<td class='text-right'>
<span t-field="server.ram"/>
</td>
</tr>
</t>
@@ -68,7 +72,10 @@
<t t-set="card_body">
<div class="row">
<div class="col-12 col-md-6">
<strong>IP Address:</strong> <span t-field="vps_server.ip_address"/>
<strong>IPv4 Address:</strong> <span t-field="vps_server.ipv4_address"/>
</div>
<div class="col-12 col-md-6">
<strong>IPv6 Address:</strong> <span t-field="vps_server.ipv6_address"/>
</div>
<div class="col-12 col-md-6">
<strong>CPU:</strong> <span t-field="vps_server.cpu"/> cores

View File

@@ -5,17 +5,33 @@
<field name="model">vps.server</field>
<field name="arch" type="xml">
<form>
<header>
<button name="action_fetch_proxmox_data" string="Fetch Proxmox Data" type="object" class="oe_highlight"/>
</header>
<sheet>
<group>
<group>
<field name="name"/>
<field name="ip_address"/>
<field name="ipv4_address"/>
<field name="ipv6_address"/>
<field name="cpu"/>
<field name="ram"/>
<field name="storage"/>
<field name="os"/>
</group>
<group>
<field name="customer_id"/>
<field name="proxmox_server_id"/>
<field name="ct_id"/>
<field name="vm_id"/>
</group>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
@@ -33,8 +49,12 @@
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="ip_address"/>
<field name="ipv4_address"/>
<field name="ipv6_address"/>
<field name="customer_id"/>
<field name="proxmox_server_id"/>
<field name="ct_id"/>
<field name="vm_id"/>
</tree>
</field>
</record>