#+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 * Models 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 ../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 ../inventory/models.py from django.db import models 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 ../inventory/models.py :padline 2 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.CharField(max_length=50) value = models.IntegerField() def __str__(self): return self.name class Meta: verbose_name_plural = "Days of Month" ordering = ['value'] 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 ../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 ../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" class DiskSize(models.Model): size = models.IntegerField() def __str__(self): return str(self.size) + " GB" class Meta: verbose_name_plural = "Disk sizes" 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) #+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 ../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 ../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 ../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 ../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.CharField(max_length=15) 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) #+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 ../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 ../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 ../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) time = models.TimeField() weekday = models.ForeignKey(Weekday, on_delete=models.CASCADE) month = models.ForeignKey(Month, on_delete=models.CASCADE) def __str__(self): return self.name class Meta: verbose_name_plural = "Cron Jobs" #+END_SRC * Admin 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 ../inventory/admin.py from django.contrib import admin from inventory.models import (GeneralDevice, Weekday, Month, 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 both RAM and disks and extended the "Computer" admin form with them. This makes it easier to add RAM modules and disks to a computer. #+BEGIN_SRC python :tangle ../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' class ComputerAdmin(admin.ModelAdmin): list_display = ('name', 'ip', 'host') inlines = (CpusInLine, RamInLine, DiskInLine,) #+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 ../inventory/admin.py :padline 2 admin.site.register(GeneralDevice) admin.site.register(Weekday) admin.site.register(Month) 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) #+END_SRC * Views Views are used to get information from the database and send them to the templates. #+BEGIN_SRC python :tangle ../inventory/views.py #!/usr/bin/python3 from django.shortcuts import get_object_or_404, render from .models import (GeneralDevice, Computer, CronJob, ComputerRamRelation, ComputerDiskRelation, ComputerCpuRelation) def index(request): device_list = GeneralDevice.objects.all() computer_list = Computer.objects.all() return render(request, 'inventory/index.html', {'device_list': device_list, 'computer_list': computer_list}) 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 = ComputerDiskRelation.objects.get(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': disks, '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}) #+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/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 ../inventory/urls.py from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index, name='index'), url(r'^device/(?P[0-9]+)/$', views.device_details, name='device'), url(r'^computer/(?P[0-9]+)/$', views.computer_details, name='computer'), url(r'^cronjob/(?P[0-9]+)/$', views.cronjob_details, name='cronjob'), ] #+END_SRC * Templates Templates define the look of the application and where things get positioned on the page. ** base.html The base.html file is the basis for all other html files and gets extended by them. #+BEGIN_SRC html :tangle ../inventory/templates/inventory/base.html Home

{% block section_title %}Device Inventory{% endblock %}

{% block content %}{% endblock %}
{% block footer %}

Created by Andreas Zweili licensed under GPL v3.0

{% endblock %}
#+END_SRC ** index.html index.html is the landing page of the project. It gives a list overview over the active devices. In addition it shows some useful information about the devices like IP addresses and similar information. #+BEGIN_SRC html :tangle ../inventory/templates/inventory/index.html {% extends "inventory/base.html" %} {% block content %} {% if device_list or computer_list %} {% else %}

No devices are available.

{% endif %} {% endblock %} #+END_SRC ** device_details.html #+BEGIN_SRC html :tangle ../inventory/templates/inventory/device_details.html {% extends "inventory/base.html" %} {% block section_title %}{{ device.name }}{% endblock %} {% block content %}

Description

{{ device.description }}

{% endblock %} #+END_SRC ** computer_details.html The computer details show all the known information about the selected computer. #+BEGIN_SRC html :tangle ../inventory/templates/inventory/computer_details.html {% extends "inventory/base.html" %} {% block section_title %}{{ computer.name }}{% endblock %} {% block content %}

Description

{{ computer.description }}

OS: {{ computer.os }}

CPU: {{ cpu.cpu }}

RAM Modules: {{ram.amount}}x {{ ram.ram }}

IP: {{ computer.ip }}

Disks: {{ disks.disk }}

Host: {{ computer.host }}

#+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 ../inventory/templates/inventory/computer_details.html :padline 0 {% if cronjob_list %}

Cron Jobs:

{% endif %} {% endblock %} #+END_SRC ** cronjob_details.html #+BEGIN_SRC html :tangle ../inventory/templates/inventory/cronjob_details.html {% extends "inventory/base.html" %} {% block section_title %}{{ cronjob.name }}{% endblock %} {% block content %}

Description

Host: {{ cronjob.host }}

Command: {{ cronjob.command }}

Time: {{ cronjob.time }}

Weekday: {{ cronjob.weekday }}

Month: {{ cronjob.month }}

{% endblock %} #+END_SRC