remove outdated documentation
literate programming is a nice idea. However IMO it's too much overhead especially for larger project. I would rather focus on writing tests.
This commit is contained in:
parent
63553a14b4
commit
e52ae11e44
|
@ -45,8 +45,3 @@ supported.
|
||||||
I would like to use this to show the usable space in a RAID system.
|
I would like to use this to show the usable space in a RAID system.
|
||||||
- [ ] calculate the used space on a host
|
- [ ] calculate the used space on a host
|
||||||
Means calculate the size all the VMs would use if they were thick.
|
Means calculate the size all the VMs would use if they were thick.
|
||||||
|
|
||||||
## Developemenet
|
|
||||||
|
|
||||||
For a detailed documentation of the source have a look at the
|
|
||||||
[documentation](https://git.2li.ch/Nebucatnetzer/network_inventory/src/branch/master/docs/docs.org).
|
|
||||||
|
|
956
docs/docs.org
956
docs/docs.org
|
@ -1,956 +0,0 @@
|
||||||
#+TITLE: Andreas Zweili
|
|
||||||
#+AUTHOR: Andreas Zweili
|
|
||||||
#+LaTeX_HEADER: \input{/home/andreas/git_repos/notes/settings/latex/style}
|
|
||||||
#+SETUPFILE: ~/git_repos/notes/settings/html_theme/setup/theme-readtheorg.setup
|
|
||||||
|
|
||||||
* inventory/models.py
|
|
||||||
|
|
||||||
Models define the database layout in a django application. Each class
|
|
||||||
represents a table in the database. A lot the models in this project
|
|
||||||
are very small because they exist mainly to keep the information unified.
|
|
||||||
|
|
||||||
** Device
|
|
||||||
|
|
||||||
The "Device" class is only used as an abstract class.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
|
|
||||||
class Device(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
description = models.TextField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** GeneralDevice
|
|
||||||
|
|
||||||
The "GeneralDevice" model is used to describe devices which are very
|
|
||||||
simple or I don't have much control over.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class GeneralDevice(Device):
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Weekday, DayOfMonth and Month
|
|
||||||
|
|
||||||
These models contain all the days of the week the days in a month and
|
|
||||||
all month in a year.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class HoursInDay(models.Model):
|
|
||||||
name = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.name)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Hours"
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
|
|
||||||
class MinutesInHour(models.Model):
|
|
||||||
name = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.name)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Minutes"
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
|
|
||||||
class Weekday(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
value = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['value']
|
|
||||||
|
|
||||||
|
|
||||||
class DayOfMonth(models.Model):
|
|
||||||
name = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.name)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Days of Month"
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
|
|
||||||
class Month(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
value = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['value']
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** RamType, Ram
|
|
||||||
|
|
||||||
"RamType" and "Ram" are ment to specify a ram module. "RamType" stands
|
|
||||||
for the DDR verions.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class RamType(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Types of RAM Modules"
|
|
||||||
|
|
||||||
|
|
||||||
class Ram(models.Model):
|
|
||||||
type = models.ForeignKey(RamType, on_delete=models.CASCADE)
|
|
||||||
size_in_gb = models.IntegerField()
|
|
||||||
ecc = models.BooleanField(default=False)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '{} {} GB'.format(self.type, self.size_in_gb)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "RAM Modules"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** DiskType, DiskSize, Disk
|
|
||||||
|
|
||||||
This three models together represent the various disk types I'm using.
|
|
||||||
The idea is that you define the type then enter a common sizes you're
|
|
||||||
using and then connect everything together in the "Disk" model.
|
|
||||||
This way you have a set of disks you can "insert" into "Computer" models.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class DiskType(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Types of disks"
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
|
|
||||||
class DiskSize(models.Model):
|
|
||||||
size = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.size) + " GB"
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Disk sizes"
|
|
||||||
ordering = ['size']
|
|
||||||
|
|
||||||
|
|
||||||
class Disk(models.Model):
|
|
||||||
type = models.ForeignKey(DiskType, on_delete=models.CASCADE)
|
|
||||||
size_in_gb = models.ForeignKey(DiskSize, on_delete=models.CASCADE)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return '{} {}'.format(self.type, self.size_in_gb)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['type']
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Architecture, CpuManufacturer and Cpu
|
|
||||||
|
|
||||||
"Architecture", "CpuManufacturer" and "Cpu" are the models which
|
|
||||||
together specifiy the properties of a CPU.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class Architecture(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
class CpuManufacturer(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "CPU Manufacturers"
|
|
||||||
|
|
||||||
|
|
||||||
class Cpu(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
manufacturer = models.ForeignKey(CpuManufacturer, on_delete=models.PROTECT)
|
|
||||||
number_of_cores = models.IntegerField()
|
|
||||||
frequency = models.FloatField()
|
|
||||||
architecture = models.ForeignKey(Architecture, on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "CPUs"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** OperatingSystem
|
|
||||||
|
|
||||||
A simple model to save operating system names.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class OperatingSystem(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Operating Systems"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Raid
|
|
||||||
|
|
||||||
A model to store the various RAID configurations.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class Raid(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Types of RAID"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Computer
|
|
||||||
|
|
||||||
This model represents a complete computer, server or virtual machine.
|
|
||||||
It's inheritated from the "Device" model. So that one can link it to a
|
|
||||||
warranty.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class Computer(Device):
|
|
||||||
os = models.ForeignKey(OperatingSystem, on_delete=models.PROTECT)
|
|
||||||
cpu = models.ManyToManyField(Cpu, through='ComputerCpuRelation')
|
|
||||||
ram = models.ManyToManyField(Ram, through='ComputerRamRelation')
|
|
||||||
ip = models.GenericIPAddressField()
|
|
||||||
disks = models.ManyToManyField(Disk, through='ComputerDiskRelation')
|
|
||||||
host = models.ForeignKey('self', null=True, blank=True,
|
|
||||||
on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.name)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['ip']
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** ComputerDiskRelation, ComputerRamRelation and ComputerCpuRelation
|
|
||||||
|
|
||||||
These models are required to link RAM modules, disks and CPUs to a computer.
|
|
||||||
Without these models it wouldn't be possible to specifiy the used amount.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class ComputerDiskRelation(models.Model):
|
|
||||||
disk = models.ForeignKey(Disk, on_delete=models.CASCADE)
|
|
||||||
computer = models.ForeignKey(Computer, on_delete=models.CASCADE)
|
|
||||||
amount = models.IntegerField()
|
|
||||||
raid = models.ForeignKey(Raid, null=True, blank=True,
|
|
||||||
on_delete=models.PROTECT)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.computer.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Disks in Computer"
|
|
||||||
|
|
||||||
|
|
||||||
class ComputerRamRelation(models.Model):
|
|
||||||
ram = models.ForeignKey(Ram, on_delete=models.CASCADE)
|
|
||||||
computer = models.ForeignKey(Computer, on_delete=models.CASCADE)
|
|
||||||
amount = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.computer.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "RAM Modules in Computer"
|
|
||||||
|
|
||||||
|
|
||||||
class ComputerCpuRelation(models.Model):
|
|
||||||
cpu = models.ForeignKey(Cpu, on_delete=models.CASCADE)
|
|
||||||
computer = models.ForeignKey(Computer, on_delete=models.CASCADE)
|
|
||||||
amount = models.IntegerField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.computer.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "CPUs in Computer"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Warranty
|
|
||||||
|
|
||||||
As the name suggests this model is for storing warranty informations.
|
|
||||||
In addition it has an attribute for a file so that one can attach a
|
|
||||||
scan of the warranty paper.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class Warranty(models.Model):
|
|
||||||
device = models.ForeignKey(Device, on_delete=models.CASCADE)
|
|
||||||
files = models.FileField()
|
|
||||||
valid_until = models.DateField()
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.device
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Warranties"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** CronJob
|
|
||||||
|
|
||||||
This model represents a cron job running on a host. It contains all
|
|
||||||
the information that one would write in a crontab file.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/models.py :padline 2
|
|
||||||
class CronJob(models.Model):
|
|
||||||
name = models.CharField(max_length=50)
|
|
||||||
host = models.ForeignKey(Computer, on_delete=models.CASCADE)
|
|
||||||
command = models.CharField(max_length=50)
|
|
||||||
minutes = models.ForeignKey(MinutesInHour, on_delete=models.CASCADE,
|
|
||||||
null=True, blank=True,)
|
|
||||||
hours = models.ForeignKey(HoursInDay, on_delete=models.CASCADE,
|
|
||||||
null=True, blank=True,)
|
|
||||||
weekday = models.ForeignKey(Weekday, on_delete=models.CASCADE,
|
|
||||||
null=True, blank=True,)
|
|
||||||
day = models.ForeignKey(DayOfMonth, on_delete=models.CASCADE,
|
|
||||||
null=True, blank=True,)
|
|
||||||
month = models.ForeignKey(Month, on_delete=models.CASCADE,
|
|
||||||
null=True, blank=True,)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = "Cron Jobs"
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
* inventory/admin.py
|
|
||||||
|
|
||||||
The admin file specifies which models are visible and in which way the
|
|
||||||
get shown in the admin interface.
|
|
||||||
|
|
||||||
We have to import each model we want to use.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/admin.py
|
|
||||||
from django.contrib import admin
|
|
||||||
from .models import (GeneralDevice, RamType, Ram, DiskType, DiskSize,
|
|
||||||
Disk, Architecture, CpuManufacturer,
|
|
||||||
Cpu, OperatingSystem, Raid, Computer,
|
|
||||||
ComputerDiskRelation,
|
|
||||||
ComputerCpuRelation,
|
|
||||||
ComputerRamRelation, Warranty, CronJob)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** InLine classes
|
|
||||||
|
|
||||||
I made an inline class for RAM, disks and CPUs and extended the
|
|
||||||
"Computer" admin form with them. This makes it easier to add theme to
|
|
||||||
a computer.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/admin.py :padline 2
|
|
||||||
class RamInLine(admin.StackedInline):
|
|
||||||
model = ComputerRamRelation
|
|
||||||
extra = 0
|
|
||||||
verbose_name_plural = 'RAM Modules'
|
|
||||||
|
|
||||||
|
|
||||||
class DiskInLine(admin.StackedInline):
|
|
||||||
model = ComputerDiskRelation
|
|
||||||
extra = 0
|
|
||||||
verbose_name_plural = 'Disks'
|
|
||||||
|
|
||||||
|
|
||||||
class CpusInLine(admin.StackedInline):
|
|
||||||
model = ComputerCpuRelation
|
|
||||||
extra = 0
|
|
||||||
verbose_name_plural = 'CPUs'
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Extended Admin Interfaces
|
|
||||||
|
|
||||||
This section contains the classes which extend the admin interface for
|
|
||||||
certain models in cases where the default form might not work for the task.
|
|
||||||
|
|
||||||
*** ComputerAdmin
|
|
||||||
|
|
||||||
The "ComputerAdmin" class extends the default "Computer" admin
|
|
||||||
interface.
|
|
||||||
For one it adds some columns to the list and adds three inline models
|
|
||||||
which allows to add them directly from the "Computer" form.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/admin.py :padline 2
|
|
||||||
class ComputerAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'ip', 'host')
|
|
||||||
inlines = (CpusInLine, RamInLine, DiskInLine,)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
*** CronJobAdmin
|
|
||||||
|
|
||||||
The "CronJobAdmin" extends the cron job admin list with two columns to
|
|
||||||
show to which host they belong.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/admin.py :padline 2
|
|
||||||
class CronJobAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('name', 'host')
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** Registering models
|
|
||||||
|
|
||||||
In order for the models to show up in the admin interface we have to
|
|
||||||
register them in addition to importing them in the admin.py file.
|
|
||||||
In addition we have to define which admin form they should use if we
|
|
||||||
want to use something different than the default one.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/admin.py :padline 2
|
|
||||||
admin.site.register(GeneralDevice)
|
|
||||||
admin.site.register(RamType)
|
|
||||||
admin.site.register(Ram)
|
|
||||||
admin.site.register(DiskType)
|
|
||||||
admin.site.register(DiskSize)
|
|
||||||
admin.site.register(Disk)
|
|
||||||
admin.site.register(Architecture)
|
|
||||||
admin.site.register(CpuManufacturer)
|
|
||||||
admin.site.register(Cpu)
|
|
||||||
admin.site.register(OperatingSystem)
|
|
||||||
admin.site.register(Raid)
|
|
||||||
admin.site.register(Computer, ComputerAdmin)
|
|
||||||
admin.site.register(Warranty)
|
|
||||||
admin.site.register(CronJob, CronJobAdmin)
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
* inventory/views.py
|
|
||||||
|
|
||||||
Views are used to get information from the database and send them to
|
|
||||||
the templates.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/views.py
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
|
||||||
from django.views.generic import ListView
|
|
||||||
from .models import (GeneralDevice, Computer, CronJob,
|
|
||||||
ComputerRamRelation,
|
|
||||||
ComputerDiskRelation,
|
|
||||||
ComputerCpuRelation)
|
|
||||||
|
|
||||||
|
|
||||||
def device_details(request, device_id):
|
|
||||||
device = get_object_or_404(GeneralDevice, pk=device_id)
|
|
||||||
return render(request, 'inventory/device_details.html',
|
|
||||||
{'device': device})
|
|
||||||
|
|
||||||
|
|
||||||
def computer_details(request, computer_id):
|
|
||||||
computer = get_object_or_404(Computer, pk=computer_id)
|
|
||||||
disks_list = ComputerDiskRelation.objects.filter(computer=computer_id)
|
|
||||||
ram = ComputerRamRelation.objects.get(computer=computer_id)
|
|
||||||
cpu = ComputerCpuRelation.objects.get(computer=computer_id)
|
|
||||||
cronjob_list = CronJob.objects.filter(host=computer_id)
|
|
||||||
return render(request, 'inventory/computer_details.html',
|
|
||||||
{'computer': computer,
|
|
||||||
'disks_list': disks_list,
|
|
||||||
'ram': ram,
|
|
||||||
'cpu': cpu,
|
|
||||||
'cronjob_list': cronjob_list})
|
|
||||||
|
|
||||||
|
|
||||||
def cronjob_details(request, cronjob_id):
|
|
||||||
cronjob = get_object_or_404(CronJob, pk=cronjob_id)
|
|
||||||
return render(request, 'inventory/cronjob_details.html',
|
|
||||||
{'cronjob': cronjob})
|
|
||||||
|
|
||||||
|
|
||||||
class ComputerList(ListView):
|
|
||||||
model = Computer
|
|
||||||
template_name = 'inventory/computer_list.html'
|
|
||||||
|
|
||||||
|
|
||||||
class CronJobList(ListView):
|
|
||||||
model = CronJob
|
|
||||||
template_name = 'inventory/cronjob_list.html'
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceList(ListView):
|
|
||||||
model = GeneralDevice
|
|
||||||
context_object_name = 'device_list'
|
|
||||||
template_name = 'inventory/device_list.html'
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
* URLs
|
|
||||||
|
|
||||||
The urls.py files contain the definitions for the URLs. This means you
|
|
||||||
can define how your various pages get accessed.
|
|
||||||
|
|
||||||
** network_inventory/urls.py
|
|
||||||
|
|
||||||
This is the main URLs file. All the urls.py files need to get
|
|
||||||
registered in here in order to work.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/network_inventory/urls.py
|
|
||||||
"""network_inventory URL Configuration
|
|
||||||
|
|
||||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
|
||||||
https://docs.djangoproject.com/en/2.0/topics/http/urls/
|
|
||||||
Examples:
|
|
||||||
Function views
|
|
||||||
1. Add an import: from my_app import views
|
|
||||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
|
||||||
Class-based views
|
|
||||||
1. Add an import: from other_app.views import Home
|
|
||||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
|
||||||
Including another URLconf
|
|
||||||
1. Import the include() function: from django.urls import include, path
|
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
|
||||||
"""
|
|
||||||
from django.conf.urls import include, url
|
|
||||||
from django.contrib import admin
|
|
||||||
from django.urls import path
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'', include('inventory.urls')),
|
|
||||||
path('admin/', admin.site.urls),
|
|
||||||
]
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** inventory/urls.py
|
|
||||||
|
|
||||||
Contains the url definitions for the inventory application. For the
|
|
||||||
moment the inventory is my only application so all the URLs will start
|
|
||||||
from the root.
|
|
||||||
|
|
||||||
#+BEGIN_SRC python :tangle ../network_inventory/inventory/urls.py
|
|
||||||
from django.conf.urls import url
|
|
||||||
|
|
||||||
from inventory import views
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
url(r'^$', views.ComputerList.as_view(), name='computers'),
|
|
||||||
url(r'^device/(?P<device_id>[0-9]+)/$',
|
|
||||||
views.device_details,
|
|
||||||
name='device'),
|
|
||||||
url(r'^computer/(?P<computer_id>[0-9]+)/$',
|
|
||||||
views.computer_details,
|
|
||||||
name='computer'),
|
|
||||||
url(r'^cronjob/(?P<cronjob_id>[0-9]+)/$',
|
|
||||||
views.cronjob_details,
|
|
||||||
name='cronjob'),
|
|
||||||
url(r'^cronjobs/$', views.CronJobList.as_view(), name='cronjobs'),
|
|
||||||
url(r'^devices/$', views.DeviceList.as_view(), name='devices'),
|
|
||||||
]
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
* Templates
|
|
||||||
|
|
||||||
Templates define the look of the application and where things get
|
|
||||||
positioned on the page.
|
|
||||||
|
|
||||||
** inventory.css
|
|
||||||
|
|
||||||
The inventory.css file get's loaded in the base.html file. It provides
|
|
||||||
some generel theming over the application.
|
|
||||||
|
|
||||||
The theme used in the inventory css is called "sakura earthly". It's
|
|
||||||
repository can be found here: https://github.com/oxalorg/sakura
|
|
||||||
I modified the theme slightly. I changed the font to sans-serif
|
|
||||||
because it makes in the inventory more sense. In addition I'm
|
|
||||||
displaying all lines in a table.
|
|
||||||
|
|
||||||
#+BEGIN_SRC css :tangle ../network_inventory/static/inventory/css/inventory.css
|
|
||||||
/* Sakura.css v1.0.0
|
|
||||||
* ================
|
|
||||||
* Minimal css theme.
|
|
||||||
* Project: https://github.com/oxalorg/sakura
|
|
||||||
*/
|
|
||||||
/* Body */
|
|
||||||
html {
|
|
||||||
font-size: 62.5%;
|
|
||||||
font-family: sans-serif; }
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
line-height: 1.618;
|
|
||||||
max-width: 38em;
|
|
||||||
margin: auto;
|
|
||||||
color: #4a4a4a;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
padding: 13px; }
|
|
||||||
|
|
||||||
@media (max-width: 684px) {
|
|
||||||
body {
|
|
||||||
font-size: 1.53rem; } }
|
|
||||||
|
|
||||||
@media (max-width: 382px) {
|
|
||||||
body {
|
|
||||||
font-size: 1.35rem; } }
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
line-height: 1.1;
|
|
||||||
font-family: Verdana, Geneva, sans-serif;
|
|
||||||
font-weight: 700;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
word-wrap: break-word;
|
|
||||||
-ms-word-break: break-all;
|
|
||||||
word-break: break-word;
|
|
||||||
-ms-hyphens: auto;
|
|
||||||
-moz-hyphens: auto;
|
|
||||||
-webkit-hyphens: auto;
|
|
||||||
hyphens: auto; }
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2.35em; }
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 2.00em; }
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.75em; }
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 1.5em; }
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
font-size: 1.25em; }
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
font-size: 1em; }
|
|
||||||
|
|
||||||
footer {
|
|
||||||
font-size: 0.5em; }
|
|
||||||
|
|
||||||
small, sub, sup {
|
|
||||||
font-size: 75%; }
|
|
||||||
|
|
||||||
hr {
|
|
||||||
border-color: #338618; }
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #338618; }
|
|
||||||
a:hover {
|
|
||||||
color: #5e5e5e;
|
|
||||||
border-bottom: 2px solid #4a4a4a; }
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 1.4em; }
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin-bottom: 0.4em; }
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
font-style: italic;
|
|
||||||
margin-left: 1.5em;
|
|
||||||
padding-left: 1em;
|
|
||||||
border-left: 3px solid #338618; }
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%; }
|
|
||||||
|
|
||||||
/* Pre and Code */
|
|
||||||
pre {
|
|
||||||
background-color: #C7E3BE;
|
|
||||||
display: block;
|
|
||||||
padding: 1em;
|
|
||||||
overflow-x: auto; }
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 0.9em;
|
|
||||||
padding: 0 0.5em;
|
|
||||||
background-color: #C7E3BE;
|
|
||||||
white-space: pre-wrap; }
|
|
||||||
|
|
||||||
pre > code {
|
|
||||||
padding: 0;
|
|
||||||
background-color: transparent;
|
|
||||||
white-space: pre; }
|
|
||||||
|
|
||||||
/* Tables */
|
|
||||||
table {
|
|
||||||
text-align: justify;
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse; }
|
|
||||||
|
|
||||||
td, th {
|
|
||||||
padding: 0.5em;
|
|
||||||
border: 1px solid #C7E3BE; }
|
|
||||||
|
|
||||||
/* Buttons, forms and input */
|
|
||||||
input, textarea {
|
|
||||||
border: 1px solid #4a4a4a; }
|
|
||||||
input:focus, textarea:focus {
|
|
||||||
border: 1px solid #338618; }
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
width: 100%; }
|
|
||||||
|
|
||||||
.button, button, input[type="submit"], input[type="reset"], input[type="button"] {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 5px 10px;
|
|
||||||
text-align: center;
|
|
||||||
text-decoration: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
background-color: #338618;
|
|
||||||
color: #f9f9f9;
|
|
||||||
border-radius: 1px;
|
|
||||||
border: 1px solid #338618;
|
|
||||||
cursor: pointer;
|
|
||||||
box-sizing: border-box; }
|
|
||||||
.button[disabled], button[disabled], input[type="submit"][disabled], input[type="reset"][disabled], input[type="button"][disabled] {
|
|
||||||
cursor: default;
|
|
||||||
opacity: .5; }
|
|
||||||
.button:focus, .button:hover, button:focus, button:hover, input[type="submit"]:focus, input[type="submit"]:hover, input[type="reset"]:focus, input[type="reset"]:hover, input[type="button"]:focus, input[type="button"]:hover {
|
|
||||||
background-color: #5e5e5e;
|
|
||||||
border-color: #5e5e5e;
|
|
||||||
color: #f9f9f9;
|
|
||||||
outline: 0; }
|
|
||||||
|
|
||||||
textarea, select, input[type] {
|
|
||||||
color: #4a4a4a;
|
|
||||||
padding: 6px 10px;
|
|
||||||
/* The 6px vertically centers text on FF, ignored by Webkit */
|
|
||||||
margin-bottom: 10px;
|
|
||||||
background-color: #C7E3BE;
|
|
||||||
border: 1px solid #C7E3BE;
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: none;
|
|
||||||
box-sizing: border-box; }
|
|
||||||
textarea:focus, select:focus, input[type]:focus {
|
|
||||||
border: 1px solid #338618;
|
|
||||||
outline: 0; }
|
|
||||||
|
|
||||||
input[type="checkbox"]:focus {
|
|
||||||
outline: 1px dotted #338618; }
|
|
||||||
|
|
||||||
label, legend, fieldset {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-weight: 600; }
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** base.html
|
|
||||||
|
|
||||||
The base.html file is the basis for all other html files and gets
|
|
||||||
extended by them.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/base.html
|
|
||||||
{% load staticfiles %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="{% static 'inventory/css/inventory.css' %}">
|
|
||||||
<title>Network Inventory</title>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<a href="{% url 'computers' %}">Computers</a> |
|
|
||||||
<a href="{% url 'devices' %}">Devices</a> |
|
|
||||||
<a href="{% url 'cronjobs' %}">Cron Jobs</a>
|
|
||||||
<h1>{% block section_title %}Device Inventory{% endblock %}</h1>
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
<footer>
|
|
||||||
{% block footer %}
|
|
||||||
<p class="copyright">Created by Andreas Zweili licensed under GPL v3.0</p>
|
|
||||||
{% endblock %}
|
|
||||||
</footer>
|
|
||||||
<script src={% static 'inventory/js/sorttable.js' %}></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** computer_list.html
|
|
||||||
|
|
||||||
computer_list.html is the landing page of the project. It gives a list
|
|
||||||
overview over the active computers. In addition it shows some useful
|
|
||||||
information about the devices like IP addresses and similar
|
|
||||||
information.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/computer_list.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}List of Computers{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% if computer_list %}
|
|
||||||
<table class="sortable">
|
|
||||||
<tr>
|
|
||||||
<th>Hostname</th>
|
|
||||||
<th>IP</th>
|
|
||||||
</tr>
|
|
||||||
{% for computer in computer_list %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'computer' computer.id %}">{{ computer.name }}</a></td>
|
|
||||||
<td>{{ computer.ip }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** device_list.html
|
|
||||||
|
|
||||||
device_list.html provides an overview about all the general devices in
|
|
||||||
addition to a link to detail page of each device.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/device_list.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}List of General Devices{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% if device_list %}
|
|
||||||
<ul>
|
|
||||||
{% for device in device_list %}
|
|
||||||
<li><a href="{% url 'device' device.id %}">{{ device.name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** cronjob_list.html
|
|
||||||
|
|
||||||
cronjob_list.html provides an overview about all the cron jobs
|
|
||||||
including the time they are running and on which computer. In addtion
|
|
||||||
it provides a link to the detail page of each cron job.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/cronjob_list.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}List of Cron Jobs{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
{% if cronjob_list %}
|
|
||||||
<table class="sortable">
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Hostname</th>
|
|
||||||
<th>Minute</th>
|
|
||||||
<th>Hour</th>
|
|
||||||
<th>Day of Week</th>
|
|
||||||
<th>Day of Month</th>
|
|
||||||
<th>Month</th>
|
|
||||||
</tr>
|
|
||||||
{% for cronjob in cronjob_list %}
|
|
||||||
<tr>
|
|
||||||
<td><a href="{% url 'cronjob' cronjob.id %}">{{ cronjob.name }}</a></td>
|
|
||||||
<td>{{ cronjob.host }}</td>
|
|
||||||
<td>{{ cronjob.minutes }}</td>
|
|
||||||
<td>{{ cronjob.hours }}</td>
|
|
||||||
<td>{{ cronjob.weekday }}</td>
|
|
||||||
<td>{{ cronjob.day }}</td>
|
|
||||||
<td>{{ cronjob.month }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** device_details.html
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/device_details.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}{{ device.name }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<h3>Description</h3>
|
|
||||||
<p>{{ device.description }}</p>
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** computer_details.html
|
|
||||||
|
|
||||||
The computer details show all the known information about the selected computer.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/computer_details.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}{{ computer.name }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<h3>Description</h3>
|
|
||||||
<p>{{ computer.description }}</p>
|
|
||||||
<p><b>OS: </b>{{ computer.os }}</p>
|
|
||||||
<p><b>CPU: </b>{{ cpu.amount }}x {{ cpu.cpu }}</p>
|
|
||||||
<p><b>RAM Modules: </b>{{ ram.amount }}x {{ ram.ram }}</p>
|
|
||||||
<p><b>IP: </b>{{ computer.ip }}</p>
|
|
||||||
{% if disks_list %}
|
|
||||||
<p><b>Disks:</b></p>
|
|
||||||
<p>
|
|
||||||
<ul>
|
|
||||||
{% for disk in disks_list %}
|
|
||||||
<li>{{ disk.amount }}x {{ disk.disk }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% if computer.host %}
|
|
||||||
<p><b>Host:</b> <a href="{% url 'computer' computer.host.id %}">{{ computer.host }}</a></p>
|
|
||||||
{% else %}
|
|
||||||
<p><b>Host:</b> None</p>
|
|
||||||
{% endif %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
The list of cron jobs running on the computer get's only displayed if
|
|
||||||
there are any cron jobs.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/computer_details.html :padline 0
|
|
||||||
{% if cronjob_list %}
|
|
||||||
<p><b>Cron Jobs:</b></p>
|
|
||||||
<p>
|
|
||||||
<ul>
|
|
||||||
{% for cronjob in cronjob_list %}
|
|
||||||
<li><a href="{% url 'cronjob' cronjob.id %}">{{ cronjob.name }}</a></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
** cronjob_details.html
|
|
||||||
|
|
||||||
The cron job details page shows all the information related to a cron job.
|
|
||||||
|
|
||||||
#+BEGIN_SRC html :tangle ../network_inventory/inventory/templates/inventory/cronjob_details.html
|
|
||||||
{% extends "inventory/base.html" %}
|
|
||||||
{% block section_title %}{{ cronjob.name }}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<h3>Description</h3>
|
|
||||||
<p>
|
|
||||||
<b>Host:</b> <a href="{% url 'computer' cronjob.host.id %}">{{ cronjob.host }}</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<b>Command:</b><br/>
|
|
||||||
<code>{{ cronjob.command }}</code>
|
|
||||||
</p>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Minute</th>
|
|
||||||
<th>Hour</th>
|
|
||||||
<th>Day of Week</th>
|
|
||||||
<th>Day of Month</th>
|
|
||||||
<th>Month</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{ cronjob.minutes }}</td>
|
|
||||||
<td>{{ cronjob.hours }}</td>
|
|
||||||
<td>{{ cronjob.weekday }}</td>
|
|
||||||
<td>{{ cronjob.day }}</td>
|
|
||||||
<td>{{ cronjob.month }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
{% endblock %}
|
|
||||||
#+END_SRC
|
|
Loading…
Reference in New Issue