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.
|
||||
- [ ] calculate the used space on a host
|
||||
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