start adding hardware info and summary tab
This commit is contained in:
parent
5dd64946b5
commit
00f6eff10a
|
@ -0,0 +1,47 @@
|
|||
from __future__ import absolute_import
|
||||
import wmi
|
||||
|
||||
|
||||
class SystemDetail:
|
||||
def __init__(self):
|
||||
self.c = wmi.WMI()
|
||||
self.make_model = self.c.Win32_ComputerSystemProduct()
|
||||
self.memory = self.c.Win32_PhysicalMemory()
|
||||
self.os = self.c.Win32_OperatingSystem()
|
||||
self.base_board = self.c.Win32_BaseBoard()
|
||||
self.bios = self.c.Win32_BIOS()
|
||||
self.disk = self.c.Win32_DiskDrive()
|
||||
self.network_adapter = self.c.Win32_NetworkAdapter()
|
||||
self.network_config = self.c.Win32_NetworkAdapterConfiguration()
|
||||
self.desktop_monitor = self.c.Win32_DesktopMonitor()
|
||||
self.cpu = self.c.Win32_Processor()
|
||||
self.usb = self.c.Win32_USBController()
|
||||
|
||||
def get_all(self, obj):
|
||||
ret = []
|
||||
for i in obj:
|
||||
tmp = [
|
||||
{j: getattr(i, j)}
|
||||
for j in list(i.properties)
|
||||
if getattr(i, j) is not None
|
||||
]
|
||||
ret.append(tmp)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def system_info():
|
||||
info = SystemDetail()
|
||||
return {
|
||||
"make_model": info.get_all(info.make_model),
|
||||
"mem": info.get_all(info.memory),
|
||||
"os": info.get_all(info.os),
|
||||
"base_board": info.get_all(info.base_board),
|
||||
"bios": info.get_all(info.bios),
|
||||
"disk": info.get_all(info.disk),
|
||||
"network_adapter": info.get_all(info.network_adapter),
|
||||
"network_config": info.get_all(info.network_config),
|
||||
"desktop_monitor": info.get_all(info.desktop_monitor),
|
||||
"cpu": info.get_all(info.cpu),
|
||||
"usb": info.get_all(info.usb),
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 3.0.3 on 2020-02-23 07:23
|
||||
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agents', '0002_auto_20200206_0554'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='agent',
|
||||
name='wmi_detail',
|
||||
field=django.contrib.postgres.fields.jsonb.JSONField(null=True),
|
||||
),
|
||||
]
|
|
@ -50,6 +50,7 @@ class Agent(models.Model):
|
|||
managed_by_wsus = models.BooleanField(default=False)
|
||||
is_updating = models.BooleanField(default=False)
|
||||
choco_installed = models.BooleanField(default=False)
|
||||
wmi_detail = JSONField(null=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.hostname
|
||||
|
|
|
@ -52,6 +52,7 @@ class AgentSerializer(serializers.ModelSerializer):
|
|||
"winupdatepolicy",
|
||||
"salt_id",
|
||||
"choco_installed",
|
||||
"wmi_detail",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,18 @@ from agents.models import Agent
|
|||
logger.configure(**settings.LOG_CONFIG)
|
||||
|
||||
|
||||
@app.task
|
||||
def get_wmi_detail_task(pk):
|
||||
sleep(30)
|
||||
agent = Agent.objects.get(pk=pk)
|
||||
resp = agent.salt_api_cmd(
|
||||
hostname=agent.salt_id, timeout=30, func="system_info.system_info"
|
||||
)
|
||||
agent.wmi_detail = resp.json()["return"][0][agent.salt_id]
|
||||
agent.save(update_fields=["wmi_detail"])
|
||||
return "ok"
|
||||
|
||||
|
||||
@app.task
|
||||
def sync_salt_modules_task(pk):
|
||||
agent = Agent.objects.get(pk=pk)
|
||||
|
|
|
@ -38,7 +38,11 @@ from checks.models import (
|
|||
CpuHistory,
|
||||
)
|
||||
from winupdate.models import WinUpdate, WinUpdatePolicy
|
||||
from agents.tasks import uninstall_agent_task, sync_salt_modules_task
|
||||
from agents.tasks import (
|
||||
uninstall_agent_task,
|
||||
sync_salt_modules_task,
|
||||
get_wmi_detail_task,
|
||||
)
|
||||
from winupdate.tasks import check_for_updates_task
|
||||
from agents.serializers import AgentHostnameSerializer
|
||||
from software.tasks import install_chocolatey, get_installed_software
|
||||
|
@ -168,6 +172,7 @@ def get_mesh_exe(request):
|
|||
response["X-Accel-Redirect"] = "/protected/meshagent.exe"
|
||||
return response
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
@authentication_classes((BasicAuthentication,))
|
||||
@permission_classes((IsAuthenticated,))
|
||||
|
@ -229,10 +234,8 @@ def accept_salt_key(request):
|
|||
return Response("accepted")
|
||||
else:
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
|
||||
|
||||
@api_view(["POST"])
|
||||
|
@ -306,7 +309,7 @@ def add(request):
|
|||
WinUpdatePolicy(agent=agent, run_time_days=[5, 6]).save()
|
||||
else:
|
||||
WinUpdatePolicy(agent=agent).save()
|
||||
|
||||
|
||||
return Response({"pk": agent.pk})
|
||||
else:
|
||||
return Response("err", status=status.HTTP_400_BAD_REQUEST)
|
||||
|
@ -354,6 +357,7 @@ def update(request):
|
|||
|
||||
sync_salt_modules_task.delay(agent.pk)
|
||||
get_installed_software.delay(agent.pk)
|
||||
get_wmi_detail_task.delay(agent.pk)
|
||||
|
||||
if not agent.choco_installed:
|
||||
install_chocolatey.delay(agent.pk, wait=True)
|
||||
|
@ -442,4 +446,3 @@ def hello(request):
|
|||
cpu.save(update_fields=["cpu_history"])
|
||||
|
||||
return Response("ok")
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
narrow-indicator
|
||||
no-caps
|
||||
>
|
||||
<q-tab name="summary" icon="fas fa-server" size="xs" label="Summary" />
|
||||
<q-tab name="checks" icon="computer" label="Checks" />
|
||||
<q-tab name="patches" label="Patches" />
|
||||
<q-tab name="software" label="Software" />
|
||||
<q-tab name="summary" icon="fas fa-info-circle" size="xs" label="Summary" />
|
||||
<q-tab name="checks" icon="fas fa-check-double" label="Checks" />
|
||||
<q-tab name="patches" icon="system_update" label="Patches" />
|
||||
<q-tab name="software" icon="fab fa-windows" label="Software" />
|
||||
</q-tabs>
|
||||
<q-separator />
|
||||
<q-tab-panels v-model="subtab" :animated="false">
|
||||
|
|
|
@ -1,26 +1,139 @@
|
|||
<template>
|
||||
<div v-if="Object.keys(summary).length === 0">
|
||||
No agent selected
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ summary.operating_system }}
|
||||
<div v-if="Object.keys(summary).length === 0">No agent selected</div>
|
||||
<div v-else>
|
||||
<span>
|
||||
<b>{{ summary.hostname }}</b>
|
||||
• {{ summary.operating_system }} • Agent v{{ summary.version }}
|
||||
</span>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<!-- left -->
|
||||
<q-list dense>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-desktop" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ makeModel }}</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-microchip" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ summary.cpu_info[0].name}}</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-memory" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ summary.total_ram}} GB RAM</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<!-- physical disks -->
|
||||
<q-item v-for="disk in physicalDisks" :key="disk.model">
|
||||
<q-item-section avatar>
|
||||
<q-icon name="far fa-hdd" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ disk.model }} {{ disk.size }}GB {{ disk.interfaceType }}</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="fas fa-globe-americas" />
|
||||
</q-item-section>
|
||||
<q-item-section>Public IP: {{ summary.public_ip}}</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</div>
|
||||
<div class="col-5"></div>
|
||||
<!-- right -->
|
||||
<div class="col-3">
|
||||
<span class="text-subtitle2 text-bold">Disks</span>
|
||||
<div v-for="disk in disks" :key="disk.device">
|
||||
<span>{{ disk.device }} ({{ disk.fstype }})</span>
|
||||
<q-linear-progress
|
||||
rounded
|
||||
size="15px"
|
||||
:value="disk.percent / 100"
|
||||
color="green"
|
||||
class="q-mt-sm"
|
||||
/>
|
||||
<span>{{ disk.free }} free of {{ disk.total }}</span>
|
||||
<hr />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
export default {
|
||||
name: 'SummaryTab',
|
||||
data() {
|
||||
return {
|
||||
|
||||
}
|
||||
name: "SummaryTab",
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
bytesToGB(bytes) {
|
||||
return Math.round(parseInt(bytes) / 1073741824);
|
||||
},
|
||||
computed: {
|
||||
summary() {
|
||||
return this.$store.state.agentSummary;
|
||||
}
|
||||
validateIPv4(ip) {
|
||||
const rx = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;
|
||||
if (rx.test(ip)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
summary() {
|
||||
return this.$store.state.agentSummary;
|
||||
},
|
||||
disks() {
|
||||
const entries = Object.entries(this.summary.disks);
|
||||
const ret = [];
|
||||
for (let [k, v] of entries) {
|
||||
ret.push(v);
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
makeModel() {
|
||||
const ret = this.summary.wmi_detail.make_model[0];
|
||||
return ret.filter(k => k.Version).map(k => k.Version)[0];
|
||||
},
|
||||
physicalDisks() {
|
||||
const ret = this.summary.wmi_detail.disk;
|
||||
const phys = [];
|
||||
ret.forEach(disk => {
|
||||
const model = disk.filter(k => k.Caption).map(k => k.Caption)[0];
|
||||
const size = disk.filter(k => k.Size).map(k => k.Size)[0];
|
||||
const interfaceType = disk
|
||||
.filter(k => k.InterfaceType)
|
||||
.map(k => k.InterfaceType)[0];
|
||||
|
||||
phys.push({
|
||||
model: model,
|
||||
size: this.bytesToGB(size),
|
||||
interfaceType: interfaceType
|
||||
});
|
||||
});
|
||||
|
||||
return phys;
|
||||
},
|
||||
localIPs() {
|
||||
const ret = this.summary.wmi_detail.network_config;
|
||||
const ips = [];
|
||||
ret.forEach(ip => {
|
||||
const x = ip.filter(k => k.IPAddress).map(k => k.IPAddress)[0];
|
||||
if (x !== undefined) {
|
||||
x.forEach(i => {
|
||||
if (this.validateIPv4(i)) {
|
||||
ips.push(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return ips;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
Loading…
Reference in New Issue