This is an old revision of the document!
Django Configuration
General Information
Configuring the Django Web Framework and its dependencies.
Checklist
Database: MariaDB
Configuring the MariaDB Database.
- Configure MariaDB to listen only on localhost
vim /etc/my.cnf [mysqld] bind-address=127.0.0.1
- Start/Enable the database
systemctl enable mariadb systemctl start mariadb
- Run secure setup
mysql_secure_installation
- Prompts for the following:
- Set database root password
- Remove anonymous users
- Disallow root logins remotely
- Remove test databases
- Reload privilege tables
- Connect to the database
mysql -u root -p
- Create your project's database
create database myprojecthere character set utf8;
- Create a database user that Django will use
create user appuserhere@localhost identified by 'PASSWORDHERE';
- Grant permissions for the app user on your project's database
grant all privileges on myprojecthere.* to appuserhere@localhost;
- Flush privileges
flush privileges;
Django
Configuring Django.
- Verify django works
python >>> import django >>> print(django.get_version()) >>> exit()
Project/App Setup
- Create a directory to store the project
mkdir /home/django cd /home/django
- Create a new Django project
django-admin startproject myprojecthere cd /home/django/myprojecthere
- Create a new Django application inside of the project
python manage.py startapp myapphere
- Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)
# Allowed Referrer Hosts (hostname and any cnames) ALLOWED_HOSTS = ['djangoserver.mycorps.domain.org','myapp.mycorps.domain.org'] # Application definition (add the application, the rest are built in) INSTALLED_APPS = [ # APPNAME.apps.APPCLASSNAME -> see ../myapphere/apps.py 'myapphere.apps.MyapphereConfig', # add your application here 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] # Static files (CSS, JavaScript, Images) #https://docs.djangoproject.com/en/1.11/howto/static-files/ STATIC_URL = '/static/' STATIC_ROOT = '/var/www/static/'
Database Setup
- Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)
# Database Configuration # https://docs.djangoproject.com/en/1.11/ref/settings/#databases DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'myprojecthere', 'USER': 'appuserhere', 'PASSWORD': 'PASSWORDHERE', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", }, } }
- Run the initial migrate command to create database tables for built in apps that come with Django
cd /home/django/myprojecthere python manage.py migrate
- Describe your data models (objects that will be stored in the database) (/home/django/myprojecthere/myapphere/models.py) EXAMPLE
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models # Asset Inventory Example class AssetEntry(models.Model): ##-- Tuples for Use in Field Choices --## #asset_type choices DEVICE_TYPES = ( ('Firewall', 'Firewall'), ('Router', 'Router'), ('Server', 'Server'), ('Storage', 'Storage'), ('Switch', 'Switch'), ('Workstation', 'Workstation'), ) # asset_env choices ENV_NAMES = ( ('Dev', 'Development'), ('Test', 'Testing'), ('Prod', 'Production'), ) # Linux OS List OS_NAMES_LINUX = ( ('CentOS 6', 'CentOS 6'), ('CentOS 7', 'CentOS 7'), ('RHEL 6', 'Red Hat Enterprise Linux 6'), ('RHEL 7', 'Red Hat Enterprise Linux 7'), ('Ubuntu 16.04', 'Ubuntu 16.04'), ('Ubuntu 18.04', 'Ubuntu 18.04'), ) # Windows OS List OS_NAMES_WINDOWS = ( ('Win 2008', 'Windows 2008'), ('Win 2012', 'Windows 2012'), ('Win 2016', 'Windows 2016'), ('Win 7', 'Windows 7'), ('Win 10', 'Windows 10'), ) # Other OS List OS_NAMES_OTHER = ( ('Cisco IOS', 'Cisco IOS'), ('Extreme XOS', 'Extreme XOS'), ('Juniper JunOS', 'Juniper JunOS'), ('NA', 'None'), ('Other', 'Other'), ('VMware ESXi', 'VMware ESXi'), ) # Combined OS List - for asset_os choices OS_NAMES = OS_NAMES_LINUX + OS_NAMES_WINDOWS + OS_NAMES_OTHER # asset_hardware choices HW_TYPES = ( ('Virtual', 'Virtual'), ('Physical', 'Physical'), ) ##-- AssetEntry Fields --## asset_name = models.CharField('Name', max_length=50) asset_type = models.CharField('Device Type', max_length=15, choices=DEVICE_TYPES) asset_description = models.CharField('Description', max_length=100) asset_env = models.CharField('Environment', max_length=15, choices=ENV_NAMES) asset_os = models.CharField('OS Name/Version', max_length = 20, choices=OS_NAMES) asset_hardware = models.CharField('Hardware: Virtual or Physical', max_length = 15, choices=HW_TYPES) # Object representation def __str__(self): return self.asset_name
- Stage changes to the database
cd /home/django/myprojecthere python manage.py makemigrations myapphere
- Make changes to the database
cd /home/django/myprojecthere python manage.py migrate
Logging Setup
- Edit project settings (/home/django/myprojecthere/myprojecthere/settings.py)
# Logging Configuration LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'verbose': { 'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s", 'datefmt' : "%d/%b/%Y %H:%M:%S", }, 'simple': { 'format': '%(levelname)s %(message)s', }, }, 'handlers': { 'file': { 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': '/var/log/myprojecthere/myapphere.log', 'maxBytes': 500000000, # 500 MB 'backupCount': 10, 'formatter': 'verbose', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'INFO', 'propagate': True, }, 'myapphere': { 'handlers': ['file'], 'level': 'INFO', }, }, } ####---- End of Logging Config ----####
- Create logging directory and setup ownership/permissions
mkdir /var/log/myprojecthere chown :apache /var/log/myprojecthere chmod g+rwx /var/log/myprojecthere
Admin Interface
- Create an admin user
python manage.py createsuperuser
- Make your models/objects available for editing in the admin portal (/home/django/myprojecthere/myapphere/admin.py)
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib import admin # Register your models here. # Make Class Available in Admin Portal (see /home/django/myprojecthere/myapphere/models.py) from .models import AssetEntry admin.site.register(AssetEntry)
URLs/Views
A URL+View will generate a web page.
URLs
Project Level URLs File
- Edit project URLs (/home/django/myprojecthere/myprojecthere/urls.py)
# add the "import include" part or you won't be able to refer to app level url files from django.conf.urls import url, include from django.contrib import admin # URL Regex Patterns - Map URIs to App's url file for additional matching urlpatterns = [ # No URI following site name (default app to use) url(r'^$', include('myapphere.urls')), # URI for app's name url(r'^myapphere/', include('myapphere.urls')), # Included /admin URI url(r'^admin/', admin.site.urls), ]
App Level URLs File
- Create a new App level URLs file (/home/django/myprojecthere/myapphere/urls.py) EXAMPLE
# urls.py - App URLs Map to App Views from django.conf.urls import url from . import views urlpatterns = [ # "/myapphere/" beginning is implied because we are in the "myapphere" urls file already # /myapphere/ - All Devices, All Environments (the index) url(r'^$', views.index, name='index'), # /myapphere/stats - All Devices, Statistics url(r'^stats/$', views.stats, name='stats'), # /myapphere/env_name - All Devices, Specific Environment url(r'^(?P<env_name>(dev|test|prod))/$', views.env, name='env'), # /myapphere/device/ - Specific Device, All Environments url(r'^(?P<device>(servers|workstations|switches|routers|firewalls))/$', views.device, name='device'), # /myapphere/device/env_name - Specific Device, Specific Environment url(r'^(?P<device>(servers|workstations|switches|routers|firewalls))/(?P<env_name>(dev|test|prod))/$', views.device_env, name='device_env'), ]
Views
- Edit the App Views that are loaded depending upon URL match(/home/django/myprojecthere/myapphere/views.py) EXAMPLE
# views.py - URLs are mapped to views # -*- coding: utf-8 -*- from __future__ import unicode_literals # Render http response+templates from django.shortcuts import render # Object or 404 from django.shortcuts import get_object_or_404 # HTTP Response from django.http import HttpResponse # Logging import logging logger = logging.getLogger(__name__) # Your Apps Model from .models import AssetEntry # /myapphere/ - All Devices, All Environments (the index) def index(request): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # Get number of assets in list number_assets = len(all_asset_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': all_asset_list, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, All Environments") # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/stats - All Devices, Statistics def stats(request): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # Get all asset device types asset_type_list = [key for key,value in AssetEntry.DEVICE_TYPES] # Get all os names os_list = [key for key,value in AssetEntry.OS_NAMES] # Log for debug purposes #for key in os_list: # logger.info("Field names are: " + key) #- Build Statistics -# # Initialize Stats list (will be a list of dictionaries) stats_list = [] ####---- Asset Counts Table: Grand Total Row ----#### sysstats_grand_total = 0 sysstats_grand_physical = 0 sysstats_grand_physical_linux = 0 sysstats_grand_physical_windows = 0 sysstats_grand_virtual = 0 sysstats_grand_virtual_linux = 0 sysstats_grand_virtual_windows = 0 sysstats_grand_vmware = 0 # Calculate stats for each type of device for device_type in asset_type_list: # Initialize an empty device stats list device_stats = [] # Add node to the device_stats list if a node from the all_asset_list matches the current device type for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): device_stats.append(node) ####---- Asset Counts Table ----#### # Total Count count_total = len(device_stats) #- Add to grand total sysstats_grand_total += count_total # Physical and Virtual Counts count_physical = 0 count_physical_linux = 0 count_physical_windows = 0 count_virtual = 0 count_virtual_linux = 0 count_virtual_windows = 0 for node in device_stats: if node.asset_hardware == "Physical": count_physical += 1 if node.asset_os.startswith("CentOS") or node.asset_os.startswith("Oracle") or node.asset_os.startswith("VMware"): # Physical+Linux Count (include physical virtual vmware hosts) count_physical_linux += 1 elif node.asset_os.startswith("Win"): # Physical+Windows Count count_physical_windows += 1 elif node.asset_hardware == "Virtual": # Virtual Count count_virtual += 1 if node.asset_os.startswith("CentOS") or node.asset_os.startswith("Oracle"): # Virtual+Linux Count count_virtual_linux += 1 elif node.asset_os.startswith("Win"): # Virtual+Windows Count count_virtual_windows += 1 #- Add to grand total physical sysstats_grand_physical += count_physical sysstats_grand_physical_linux += count_physical_linux sysstats_grand_physical_windows += count_physical_windows #- Add to grand total virtual sysstats_grand_virtual += count_virtual sysstats_grand_virtual_linux += count_virtual_linux sysstats_grand_virtual_windows += count_virtual_windows ####---- OS Counts Table ----#### # Initialize a new empty OS Counts List os_counts = [] # Add all the os names and an initial count of 0 for name in os_list: os_counts.append({ 'os_name': name, 'count': 0 }) # Check each node in the devices specific stats for node in device_stats: # Compare node's OS against each os name in the os_counts list and increment count if a match is found for os_entry in os_counts: if os_entry['os_name'] == node.asset_os: # Increment count value on an os name match os_entry['count'] += 1 ####---- After All Stats Calculations: Add Device Stats to stats_list ----#### # Add device statistics to stats_list stats_list.append({ 'asset_type': device_type, 'total': count_total, 'physical': count_physical, 'physical_linux': count_physical_linux, 'physical_windows': count_physical_windows, 'virtual': count_virtual, 'virtual_linux': count_virtual_linux, 'virtual_windows': count_virtual_windows, 'os_count_stats': os_counts }) # Grand Total Only: VMware ESXi Host Count for node in device_stats: if node.asset_os.startswith("VMware"): sysstats_grand_vmware += 1 #-- END OF Calculate Device Type Stats loop --# ##-- Calculate OS stats grand totals --## # Initialize a new empty OS Counts Total List os_counts_total = [] # Add all the os names and an initial count of 0 for name in os_list: os_counts_total.append({ 'os_name': name, 'count': 0}) # For each device specific stats entry, add up grand total os counts for device_entry in stats_list: # For each device_entry in the stats_list, go through its os_count_stats value, which is a list of os_names and counts for os_device_entry in device_entry['os_count_stats']: # Check each os_count_stats os_name against the os_counts_total os_name list for os_entry_total in os_counts_total: # If we have an os_name match, add the device's os count to the total os count if os_entry_total['os_name'] == os_device_entry['os_name']: os_entry_total['count'] += os_device_entry['count'] ####---- Add grand totals to stats_list ----#### stats_list.append({ 'asset_type': 'Total', 'total': sysstats_grand_total, 'physical': sysstats_grand_physical, 'physical_linux': sysstats_grand_physical_linux, 'physical_windows': sysstats_grand_physical_windows, 'virtual': sysstats_grand_virtual, 'virtual_linux': sysstats_grand_virtual_linux, 'virtual_windows': sysstats_grand_virtual_windows, 'os_count_stats': os_counts_total }) #- Other Grand Totals: Calculate -# sysstats_grand_linux = sysstats_grand_physical_linux + sysstats_grand_virtual_linux sysstats_grand_windows = sysstats_grand_physical_windows + sysstats_grand_virtual_windows # Map template variable names (1st) to the Python variables (2nd) for use in templates context = {'device_stats': stats_list, 'total_linux': sysstats_grand_linux, 'total_windows': sysstats_grand_windows, 'total_vmware': sysstats_grand_vmware, 'os_list': os_list} # Logging logger.info("Rendering stats.html") # Render the HTTP request, using the template, passing the context return render(request, 'myapphere/stats.html', context) # /myapphere/env_name - All Devices, Specific Environment def env(request, env_name): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for the asset types in the passed environment only new_list = [] # Check each asset, add to new list if it matches the requested environment name for node in all_asset_list: if ''.join(node.asset_env.lower().split()) == env_name.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'env': env_name, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, " + env_name) # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/device/ - Specific Device, All Environments def asset_type_all_env(request, device_type): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for specific devices only new_list = [] # Check each asset, add to new list if it matches the requested device type for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'asset_type': device_type, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - Devices: " + device_type + ", All Environments") # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/device/env_name - Specific Device, Specific Environment def type_env(request, device_type, env_name): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for specific devices and environment only new_list = [] # Check each asset, add to new list if it matches the requested device and environment for node in all_asset_list: if ''.join(node.asset_type.lower().split()) == device_type.lower(): if ''.join(node.asset_env.lower().split()) == env_name.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to Python variables (2nd) for use in html templates context = { 'all_asset_list': new_list, 'asset_type': device_type, 'env': env_name, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - Devices: " + device_type + ", Env: " + env_name) # Render the http request, using the template, passing the context return render(request, 'myapphere/index.html', context) # /myapphere/<asset_hardware>/ - Physical or Virtual def asset_hardware(request, asset_hardware): # Get all asset objects all_asset_list = AssetEntry.objects.order_by('asset_type', 'asset_env', 'asset_name') # New List for asset_hardware (physical or virtual) new_list = [] # Check each asset, add to new list if it matches the requested hardware type for node in all_asset_list: if ''.join(node.asset_hardware.lower().split()) == asset_hardware.lower(): new_list.append(node) # Get number of assets in list number_assets = len(new_list) # Map template variable names (1st) to the Python variables (2nd) for use in templates context = {'all_asset_list': new_list, 'asset_hardware': asset_hardware, 'asset_count': number_assets } # Logging logger.info("Rendering index.html - All Devices, " + asset_hardware) # Render the HTTP request, using the template, passing the context return render(request, 'myapphere/index.html', context)
Web Page Templates
Creating the web page templates.
- Create directory structure
mkdir -p /home/django/myprojecthere/myapphere/templates/myapphere
- Create new pages
- templates/myapphere/index.html
- templates/myapphere/stats.html
Page Content: Index
Example page content for the index.html page.
/home/django/myprojecthere/myapphere/templates/myapphere/index.html
<!DOCTYPE html> <html> <head> <title>Asset List</title> </head> <body> {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'myapphere/style.css' %}" /> <!-- Export button jquery (https://github.com/kayalshri/tableExport.jquery.plugin) --> <script type="text/javascript" src="{% static 'js/jquery.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/tableExport.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/jquery.base64.js' %}"></script> <!-- Layout Divide: Left Side Menu for Devices --> <table class="layout"> <tr> <!-- For white gaps in between Device Types and Phys/Virt, this must be larger than stylesheet width --> <!-- Set to style sheet width+25 px --> <td class="layout" width="696px"> <!-- Device Menu: Determine Active Device --> <ul class="asset_type"> {% if not asset_type %} <li><a class="active" href="/myapphere/">All Devices</a></li> {% else %} <li><a href="/myapphere/">All Devices</a></li> {% endif %} {% if asset_type == 'firewalls' %} <li><a class="active" href="/myapphere/firewalls/">Firewalls</a></li> {% else %} <li><a href="/myapphere/firewalls/">Firewalls</a></li> {% endif %} {% if asset_type == 'routers' %} <li><a class="active" href="/myapphere/routers/">Routers</a></li> {% else %} <li><a href="/myapphere/routers/">Routers</a></li> {% endif %} {% if asset_type == 'servers' %} <li><a class="active" href="/myapphere/servers/">Servers</a></li> {% else %} <li><a href="/myapphere/servers/">Servers</a></li> {% endif %} {% if asset_type == 'storage' %} <li><a class="active" href="/myapphere/storage/">Storage</a></li> {% else %} <li><a href="/myapphere/storage/">Storage</a></li> {% endif %} {% if asset_type == 'switches' %} <li><a class="active" href="/myapphere/switches/">Switches</a></li> {% else %} <li><a href="/myapphere/switches/">Switches</a></li> {% endif %} {% if asset_type == 'workstations' %} <li><a class="active" href="/myapphere/workstations/">Workstations</a></li> {% else %} <li><a href="/myapphere/workstations/">Workstations</a></li> {% endif %} </ul> </td> <!-- END of Layout Divide: Left Side Menu for Devices --> <!-- Layout Divide: Right Side Phys and Virt Links --> <!-- For white gaps in between Phys/Virt and Stats, this must be larger than stylesheet width --> <!-- Set to style sheet width+25 px --> <td class="layout" width="188px"> <!-- Asset Type Menu: Physical and Virtual --> <ul class ="asset_hardware"> {% if asset_hardware == 'physical' %} <li><a class="active" href="/myapphere/physical/">Physical</a></li> <li><a href="/myapphere/virtual/">Virtual</a></li> {% elif asset_hardware == 'virtual' %} <li><a href="/myapphere/physical/">Physical</a></li> <li><a class="active" href="/myapphere/virtual/">Virtual</a></li> {% else %} <li><a href="/myapphere/physical/">Physical</a></li> <li><a href="/myapphere/virtual/">Virtual</a></li> {% endif %} </ul> </td> <!-- END of Layout Divide: Right Side Phys and Virt Links --> <!-- Layout Divide: Right Side Additional Links --> <td class="layout"> <ul class="stats"> <li><a href="/myapphere/stats/">Stats</a></li> </ul> </td> <!-- END of Layout Divide: Right Side Additional Links --> </tr> <!-- Layout Divide: Left Side Environment Menu --> <tr> <td class="layout"> <!-- Environment Menu: Dynamic Asset Type Links --> <ul class="env"> {% if env == 'dev' %} {% if asset_type %} <li><a class="active" href="/myapphere/{{ asset_type }}/dev/">Dev</a></li> <li><a href="/myapphere/{{ asset_type }}/test/">Test</a></li> <li><a href="/myapphere/{{ asset_type }}/prod/">Prod</a></li> {% else %} <li><a class="active"href="/myapphere/dev/">Dev</a></li> <li><a href="/myapphere/test/">Test</a></li> <li><a href="/myapphere/prod/">Prod</a></li> {% endif %} {% elif env == 'test' %} {% if asset_type %} <li><a href="/myapphere/{{ asset_type }}/dev/">Dev</a></li> <li><a class="active" href="/myapphere/{{ asset_type }}/test/">Test</a></li> <li><a href="/myapphere/{{ asset_type }}/prod/">Prod</a></li> {% else %} <li><a href="/myapphere/dev/">Dev</a></li> <li><a class="active" href="/myapphere/test/">Test</a></li> <li><a href="/myapphere/prod/">Prod</a></li> {% endif %} {% elif env == 'prod' %} {% if asset_type %} <li><a href="/myapphere/{{ asset_type }}/dev/">Dev</a></li> <li><a href="/myapphere/{{ asset_type }}/test/">Test</a></li> <li><a class="active" href="/myapphere/{{ asset_type }}/prod/">Prod</a></li> {% else %} <li><a href="/myapphere/dev/">Dev</a></li> <li><a href="/myapphere/test/">Test</a></li> <li><a class="active" href="/myapphere/prod/">Prod</a></li> {% endif %} {% else %} {% if asset_type %} <li><a href="/myapphere/{{ asset_type }}/dev/">Dev</a></li> <li><a href="/myapphere/{{ asset_type }}/test/">Test</a></li> <li><a href="/myapphere/{{ asset_type }}/prod/">Prod</a></li> {% else %} <li><a href="/myapphere/dev/">Dev</a></li> <li><a href="/myapphere/test/">Test</a></li> <li><a href="/myapphere/prod/">Prod</a></li> {% endif %} {% endif %} </ul> </td> <!-- END of Layout Divide: Left Side Environment Menu --> <!-- START of Layout Divide: 2nd row for logged in message --> <td class="layout"> {% if user.is_authenticated %} Logged in: {{ user.username }}<br> <a class="plain" href="/logout/">Logout</a> {% endif %} </td> </tr> <!-- END of Layout Divide: 2nd row for logged in message --> <!-- Layout Divide: Bottom Asset List Table --> <tr> <td class="layout" colspan=3> <!-- Asset List Above Table: Display Device and Environment --> <br> {% if asset_type == 'firewalls' %} {% if env == 'dev' %} <b>Asset List - Firewalls - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Firewalls - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Firewalls - Production Environment</b> {% else %} <b>Asset List - Firewalls - All Environments</b> {% endif %} {% elif asset_type == 'routers' %} {% if env == 'dev' %} <b>Asset List - Routers - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Routers - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Routers - Production Environment</b> {% else %} <b>Asset List - Routers - All Environments</b> {% endif %} {% elif asset_type == 'servers' %} {% if env == 'dev' %} <b>Asset List - Servers - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Servers - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Servers - Production Environment</b> {% else %} <b>Asset List - Servers - All Environments</b> {% endif %} {% elif asset_type == 'storage' %} {% if env == 'dev' %} <b>Asset List - Storage - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Storage - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Storage - Production Environment</b> {% else %} <b>Asset List - Storage - All Environments</b> {% endif %} {% elif asset_type == 'switches' %} {% if env == 'dev' %} <b>Asset List - Switches - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Switches - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Switches - Production Environment</b> {% else %} <b>Asset List - Switches - All Environments</b> {% endif %} {% elif asset_type == 'workstations' %} {% if env == 'dev' %} <b>Asset List - Workstations - Development Environment</b> {% elif env == 'test' %} <b>Asset List - Workstations - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - Workstations - Production Environment</b> {% else %} <b>Asset List - Workstations - All Environments</b> {% endif %} {% else %} {% if env == 'dev' %} <b>Asset List - All Types - Development Environment</b> {% elif env == 'test' %} <b>Asset List - All Types - Test Environment</b> {% elif env == 'prod' %} <b>Asset List - All Types - Production Environment</b> {% else %} <b>Asset List - All Types - All Environments</b> {% endif %} {% endif %} <!-- Physical/Virtual Filter --> {% if asset_hardware %} {% if asset_hardware == 'physical' %} <b> - Physical -</b> {% elif asset_hardware == 'virtual' %} <b> - Virtual -</b> {% endif %} {% endif %} <!-- Assets List Above Table: Number of Assets Displayed --> {% if asset_count %} {% if asset_count == 1 %} <b> ({{ asset_count }} asset)</b> {% else %} <b> ({{ asset_count }} assets)</b> {% endif %} {% else %} <b> (0 assets)</b> {% endif %} <!-- Export Buttons --> <a href="#" class="plain" onclick="$('#assetlist').tableExport({type:'csv',escape:'false'});"><img src="{% static 'myapphere/csv.png' %}" width="24px" title="Export CSV"></a> <a href="#" class="plain" onclick="$('#assetlist').tableExport({type:'excel',escape:'false'});"><img src="{% static 'myapphere/xls.png' %}" width="24px" title="Export Excel"></a> <br> <!-- The Assets List Table --> <table class="myapphere" id="assetlist"> <thead> <tr class="myapphere"> <th class="myapphere">Device</th> <th class="myapphere">Name</th> <th class="myapphere">Description</th> <th class="myapphere">Environment</th> <th class="myapphere">OS</th> <th class="myapphere">Type</th> </tr> </thead> <tbody {% for name in all_assets_list %} <tr class="myapphere"> <td class="myapphere">{{ name.asset_type }}</td> <td class="myapphere">{{ name.asset_name }}</td> <td class="myapphere">{{ name.asset_description }}</td> <td class="myapphere center">{{ name.asset_env }}</td> <td class="myapphere center">{{ name.asset_os }}</td> <td class="myapphere center">{{ name.asset_hardware }}</td> </tr> {% endfor %} </tbody> </table> <!-- END of Assets List Table --> </td> </tr> </table> <!-- END of Layout Divide: Bottom Assets List Table --> <br> <hr> <br> </body> </html>
Page Content: Stats
Example page content for the stats.html page.
/home/django/myprojecthere/myapphere/templates/myapphere/stats.html
<!DOCTYPE html> <html> <head> <title>Asset List - Stats</title> </head> <body> {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'myapphere/style.css' %}" /> <!-- Export button jquery (https://github.com/kayalshri/tableExport.jquery.plugin) --> <script type="text/javascript" src="{% static 'js/jquery.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/tableExport.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/jquery.base64.js' %}"></script> <!-- Layout Divide: Left Side Menu for Devices --> <table class="layout"> <tr> <!-- For white gaps in between Device Types and Phys/Virt, this must be larger than stylesheet width --> <!-- Set to style sheet width+25 px --> <td class="layout" width="696px"> <!-- Device Menu: No Devices Active on Stats Page --> <ul class="asset_type"> <li><a href="/myapphere/">All Devices</a></li> <li><a href="/myapphere/firewalls/">Firewalls</a></li> <li><a href="/myapphere/routers/">Routers</a></li> <li><a href="/myapphere/servers/">Servers</a></li> <li><a href="/myapphere/storage/">Storage</a></li> <li><a href="/myapphere/switches/">Switches</a></li> <li><a href="/myapphere/workstations/">Workstations</a></li> </ul> </td> <!-- END of Layout Divide: Left Side Menu for Devices --> <!-- Layout Divide: Right Side Phys and Virt Links --> <!-- For white gaps in between Phys/Virt and Stats, this must be larger than stylesheet width --> <!-- Set to style sheet width+25 px --> <td class="layout" width="188px"> <!-- Asset Type Menu: Physical and Virtual --> <ul class ="asset_hardware"> {% if asset_hardware == 'physical' %} <li><a class="active" href="/myapphere/physical/">Physical</a></li> <li><a href="/myapphere/virtual/">Virtual</a></li> {% elif asset_hardware == 'virtual' %} <li><a href="/myapphere/physical/">Physical</a></li> <li><a class="active" href="/myapphere/virtual/">Virtual</a></li> {% else %} <li><a href="/myapphere/physical/">Physical</a></li> <li><a href="/myapphere/virtual/">Virtual</a></li> {% endif %} </ul> </td> <!-- END of Layout Divide: Right Side Phys and Virt Links --> <!-- Layout Divide: Right Side Additional Links --> <td class="layout"> <ul class="stats"> <li><a class="active" href="/myapphere/stats/">Stats</a></li> </ul> </td> <!-- END of Layout Divide: Right Side Additional Links --> </tr> <!-- START of Layout Divide: 2nd row for logged in message --> <tr> <td class="layout"> </td> <td class="layout"> {% if user.is_authenticated %} Logged in: {{ user.username }}<br> <a class="plain" href="/logout/">Logout</a> {% endif %} </td> </tr> <!-- END of Layout Divide: 2nd row for logged in message --> <!-- Layout Divide: Bottom Stats Table (Asset Counts) --> <tr> <td class="layout" colspan=3> <br> <b>Asset List - Statistics - Asset Counts</b> <!-- Export Buttons --> <a href="#" class="plain" onclick="$('#assetcounts').tableExport({type:'csv',escape:'false'});"><img src="{% static 'myapphere/csv.png' %}" width="24px" title="Export CSV"></a> <a href="#" class="plain" onclick="$('#assetcounts').tableExport({type:'excel',escape:'false'});"><img src="{% static 'myapphere/xls.png' %}" width="24px" title="Export Excel"></a> <br> <!-- Stats Table (Asset Counts) --> <table class="myapphere" id="assetcounts"> <thead> <tr class="myapphere"> <th class="myapphere">Device Type</th> <th class="myapphere">Systems</th> <th class="myapphere">Physical</th> <th class="myapphere">Physical Linux</th> <th class="myapphere">Physical Windows</th> <th class="myapphere">Virtual</th> <th class="myapphere">Virtual Linux</th> <th class="myapphere">Virtual Windows</th> </tr> </thead> <tbody> {% for asset in device_stats %} <tr class="myapphere"> {% if asset.asset_type == 'Total' %} <td class="myapphere totals"><b>{{ asset.asset_type }}</b></td> <td class="myapphere center totals">{{ asset.total }}</td> <td class="myapphere center totals">{{ asset.physical }}</td> <td class="myapphere center totals">{{ asset.physical_linux }}</td> <td class="myapphere center totals">{{ asset.physical_windows }}</td> <td class="myapphere center totals">{{ asset.virtual }}</td> <td class="myapphere center totals">{{ asset.virtual_linux }}</td> <td class="myapphere center totals">{{ asset.virtual_windows }}</td> {% else %} <td class="myapphere">{{ asset.asset_type }}</td> <td class="myapphere center">{{ asset.total }}</td> <td class="myapphere center">{{ asset.physical }}</td> <td class="myapphere center">{{ asset.physical_linux }}</td> <td class="myapphere center">{{ asset.physical_windows }}</td> <td class="myapphere center">{{ asset.virtual }}</td> <td class="myapphere center">{{ asset.virtual_linux }}</td> <td class="myapphere center">{{ asset.virtual_windows }}</td> {% endif %} </tr> {% endfor %} <tr class="myapphere"> <td class="myapphere totals">Total Linux</td> <td class="myapphere center">{{ total_linux }}</td> </tr> <tr class="myapphere"> <td class="myapphere totals">Total Windows</td> <td class="myapphere center">{{ total_windows }}</td> </tr> <tr class="myapphere"> <td class="myapphere totals">Total VMware ESXi*</td> <td class="myapphere center">{{ total_vmware }}</td> </tr> </tbody> </table> *Physical Virtual Hosts (VMware ESXi) count is included in Physical Linux/Total Linux counts. <!-- END of Stats Table (Asset Counts) --> </td> </tr> <!-- END of Layout Divide: Bottom Stats Table (Asset Counts) --> <!-- Layout Divide: Bottom Stats Table (OS Counts) --> <tr> <td class="layout" colspan=3> <br> <b>Asset List - Statistics - OS Counts</b> <!-- Export Buttons --> <a href="#" class="plain" onclick="$('#oscounts').tableExport({type:'csv',escape:'false'});"><img src="{% static 'myapphere/csv.png' %}" width="24px" title="Export CSV"></a> <a href="#" class="plain" onclick="$('#oscounts').tableExport({type:'excel',escape:'false'});"><img src="{% static 'myapphere/xls.png' %}" width="24px" title="Export Excel"></a> <br> <!-- Stats Table (OS Counts) --> <table class="myapphere" id="oscounts"> <thead> <tr class="myapphere"> <th class="myapphere">Device Type</th> {% for os_name in os_list %} <th class="myapphere">{{ os_name }}</th> {% endfor %} </tr> </thead> <tbody> {% for asset in device_stats %} <tr class="myapphere"> {% if asset.asset_type == 'Total' %} <td class="myapphere totals"><b>{{ asset.asset_type }}</b></td> {% for name in asset.os_count_stats %} <td class="myapphere center totals">{{ name.count }}</td> {% endfor %} {% else %} <td class="myapphere">{{ asset.asset_type }}</td> {% for name in asset.os_count_stats %} <td class="myapphere center">{{ name.count }}</td> {% endfor %} {% endif %} </tr> {% endfor %} </tbody> </table> <!-- END of Stats Table (OS Counts) --> </td> </tr> </table> <!-- END of Layout Divide: Bottom Stats Table (OS Counts) --> <br> <hr> <br> </body> </html>
Static Files/Stylesheets
Configuring stylesheets.
- Create directory structure
mkdir -p /home/django/myprojecthere/myapphere/static/myapphere
- Create stylesheet (/home/django/myprojecthere/myapphere/static/myapphere/style.css)
/* style.css : Styles for html templates */ /* ---- Table Styles ---- */ /* table settings */ table.layout { border-collapse: collapse; border-spacing: 0px; padding: 0px; } td.layout { border-spacing: 0px; padding: 0px; } table.myapphere { border-collapse: collapse; } /* table headers, table definitions */ table.myapphere, th.myapphere, td.myapphere { border-collapse: collapse; border: 1px solid #ddd; padding: 5px; } /* th -> table headers */ th.myapphere { background-color: #4CAF50; color: white; } /* tr -> table rows * * tr:nth-child -> color every even table row * * tr:hover -> Mouse hover background color effect */ tr.myapphere:nth-child(even) {background-color: #f2f2f2;} tr.myapphere:hover {background-color: #ddd;} td.center { text-align: center; } td.totals { background-color: #b3b3b3; font-weight: bold; } /* ---- Menu Styles ---- */ ul.asset_type { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 671px; } ul.env { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 163px; } ul.stats { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 60px; } ul.asset_hardware { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; width: 163px; } li { float: left; } li a { display: block; color: white; text-align: center; padding: 10px 10px; text-decoration: none; } a:hover:not(.active) { background-color: #111; } .active { background-color:#4CAF50; } /* ---- Non-Menu Styles ---- */ a:link.plain { background-color: #ffffff; } a:visited.plain { background-color: #ffffff; } a:hover.plain { background-color: #4caf50; }
Apache
Configuring Apache to pass traffic to the application.
- Configure Apache's mod_wsgi for the application (new file)
vim /etc/httpd/conf.d/myapphere.conf # Asset List Django/WSGI Config # WSGIScriptAlias: The base URL to serve the application from WSGIScriptAlias / /home/django/myprojecthere/myprojecthere/wsgi.py # WSGI Daemon Process Config WSGIDaemonProcess myapphere python-path=/home/django/myprojecthere WSGIProcessGroup myapphere # Location of Django Application and wsgi.py config <Directory /home/django/myprojecthere/myprojecthere> <Files wsgi.py> Require all granted </Files> </Directory> # Static files (admin interface and style sheet) Alias /static/ /var/www/static/ <Directory /var/www/static/> Require all granted </Directory>
- Configure the virtual host (new file)
vim /etc/httpd/conf.d/vhosts.conf # Virtual Host Config # Redirect shortname to fully qualified <VirtualHost *:80> ServerName djangoserver Redirect "/" "http://djangoserver.mycorps.domain.org/" </VirtualHost> # Redirect all http to https <VirtualHost *:80> ServerName djangoserver.mycorps.domain.org <IfModule mod_rewrite.c> # Redirect all to https RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} </IfModule> </VirtualHost> # Redirect shortname to fully qualified <VirtualHost *:443> ServerName djangoserver Redirect "/" "https://djangoserver.mycorps.domain.org/" </VirtualHost> # Django Application lives here at the root /. See: /etc/httpd/conf.d/myapphere.conf <VirtualHost *:443> # Fully qualified server name ServerName djangoserver.mycorps.domain.org Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;" </VirtualHost> <VirtualHost *:443> # OPTIONAL: CNAME for website - will only work with SSL if using a wildcard certificate ServerName myapphere.mycorps.domain.org Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;" </VirtualHost>
- Configure SSL Certificate
vim /etc/httpd/conf.d/ssl.conf SSLCertificateFile /etc/pki/tls/certs/current_crt.crt SSLCertificateKeyFile /etc/pki/tls/certs/current_key.key SSLCertificateChainFile /etc/pki/tls/certs/current_ca.crt
- Generate a self signed cert if this is just a lab environment.
- Start and Enable Apache
systemctl start httpd systemctl enable httpd
Django: Authentication
Adding authentication to Django requires basic auth to be setup first, as LDAP auth builds upon it.
Basic Authentication
Basic authentication uses Django local user accounts.
- Edit Project Settings (/home/django/myprojecthere/myprojecthere/settings.py)
# Redirect Successful Logins Here LOGIN_REDIRECT_URL = '/myapphere/' # Ensure contrib.auth is added to installed apps: # Application definition INSTALLED_APPS = [ 'myapphere.apps.MyapphereConfig', 'django.contrib.admin', 'django.contrib.auth', # must exist for basic auth to work ... ]
- Add login and logout URLs to project URLs (/home/django/myprojecthere/myprojecthere/urls.py)
# auth views - authentication login/logout module from django.contrib.auth import views as auth_views # URL Patterns - Map to Projects Within Django urlpatterns = [ ... # Login URLs url(r'^login/$', auth_views.login, {'template_name': 'login.html'}, name='login'), url(r'^logout/$', auth_views.logout, {'next_page': '/login/'}, name='logout'), ... ]
- Edit the application views (/home/django/myprojecthere/myapphere/views.py)
# Require login decorator from django.contrib.auth.decorators import login_required # Put login decorator before every function definition that you want to require login to view: #-> Require login for the view following it <-# @login_required(login_url="/login/") def index(request):
- Create a HTML Login Page (/home/django/myprojecthere/myapphere/templates/login.html)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{% block title %}Asset List{% endblock %}</title> </head> <body> <header> <h1>Asset List</h1> {% if user.is_authenticated %} Greetings, {{ user.username }}. <a href="{% url 'logout' %}">logout</a> {% endif %} </header> <hr> <main> <h2>Login</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Login</button> </form> </main> <hr> </body> </html>
LDAP Authentication
Configuring LDAP authentication.
- Install the python django ldap package
pip install django-auth-ldap
- Edit Project Settings (/home/django/myprojecthere/myprojecthere/settings.py)
# LDAP Module Imports import ldap from django_auth_ldap.config import LDAPSearch from django_auth_ldap.config import GroupOfNamesType from django_auth_ldap.config import LDAPGroupQuery # Authentication Backends (LDAP and Django Local) AUTHENTICATION_BACKENDS = ( 'django_auth_ldap.backend.LDAPBackend', 'django.contrib.auth.backends.ModelBackend', ) ####- LDAP Server Config -#### AUTH_LDAP_SERVER_URI = "ldap://LDAPSERVER01.mycorps.domain.org ldap://LDAPSERVER02.mycorps.domain.org" AUTH_LDAP_START_TLS = True # Bind Info: Use authenticating user to get user and group info AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,cn=users,cn=accounts,dc=mycorps,dc=domain,dc=org" # Cache LDAP Groups for use with permissions AUTH_LDAP_CACHE_GROUPS = True AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600 # Group Info Gathering AUTH_LDAP_GROUP_SEARCH = LDAPSearch "cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org", ldap.SCOPE_SUBTREE, "(objectClass=groupofnames)" ) AUTH_LDAP_GROUP_TYPE = GroupOfNamesType() # Group restrictions - Who can login via LDAP AUTH_LDAP_REQUIRE_GROUP = ( # Allow login for members of the LDAP group "list_users" LDAPGroupQuery("cn=list_users,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org") | # Allow login for members of the LDAP group "admin_group" LDAPGroupQuery("cn=admin_group,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org") ) # Use LDAP group membership to calculate group permissions. AUTH_LDAP_FIND_GROUP_PERMS = True # Update Django record from LDAP each time user logs in AUTH_LDAP_ALWAYS_UPDATE_USER = True # Populate the Django user info from LDAP directory info AUTH_LDAP_USER_ATTR_MAP = { "first_name": "givenname", "last_name": "sn", "email": "mail" } # Set user permission flags by group - set LDAP group "admin_group" as Django Staff Members AUTH_LDAP_USER_FLAGS_BY_GROUP = { "is_staff": "cn=admin_group,cn=groups,cn=accounts,dc=mycorps,dc=domain,dc=org" }
Django: Jquery
Jquery can be added in order to enable an Export as CSV and/or Excel buttons.
Reference: Export Jquery Buttons: https://github.com/kayalshri/tableExport.jquery.plugin
- From the reference link, download:
- jquery.base64.js
- tableExport.js
- Search the internet for CSV and XLS icons. Download them.
- CSV = save as “csv.png”
- XLS = save as “xls.png”
- Save the Javascript files and small pictures (CSV/XLS) into the same directory as the style sheet
/home/django/myprojecthere/myapphere/static/myapphere/
- Install the Django Jquery integration
pip install django-jquery
- Add Jquery to the “INSTALLED_APPS” list (/home/django/myprojecthere/myprojecthere/settings.py)
# Application definition INSTALLED_APPS = [ 'jquery',
- Add jquery to HTML templates
<!-- Export button jquery support (https://github.com/kayalshri/tableExport.jquery.plugin) --> <script type="text/javascript" src="{% static 'js/jquery.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/tableExport.js' %}"></script> <script type="text/javascript" src="{% static 'myapphere/jquery.base64.js' %}"></script> <!-- Export Buttons --> <a href="#" class="plain" onclick="$('#assetlist').tableExport({type:'csv',escape:'false'});"><img src="{% static 'myapphere/csv.png' %}" width="24px" title="Export CSV"></a> <a href="#" class="plain" onclick="$('#assetlist').tableExport({type:'excel',escape:'false'});"><img src="{% static 'myapphere/xls.png' %}" width="24px" title="Export Excel"></a>
- Collect static files
cd /home/django/myprojecthere/ python manage.py collectstatic