Skip to content

Feature Update: Unit Tests, Ticket Sorting, View Template Addons, Fault Tolerant Commands #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
b31cce1
Align with fork repo
Auwate Mar 20, 2024
74d43d8
Updated settings-dev.py to turn HTTPS off (FOR PRODUCTION)
Auwate Mar 20, 2024
74baa0f
Changes:
Auwate Mar 25, 2024
686f960
PRODUCTION CHANGE:
Auwate Mar 25, 2024
e46544d
ADDED README AND DEV_TIPS
Auwate Mar 25, 2024
037ea75
CHANGES:
Auwate Mar 25, 2024
88e1f2f
CHANGES:
Auwate Mar 25, 2024
5963cea
Changes:
Auwate Mar 25, 2024
3ddb08d
Changes:
Auwate Mar 25, 2024
672f003
Development
Auwate Mar 25, 2024
3adddb8
-
Auwate Mar 25, 2024
214a4b1
-
Auwate Mar 25, 2024
10e7062
Changes:
Auwate Mar 26, 2024
c508bf1
Merged changes
Auwate Mar 26, 2024
8b3e69a
Removed UTC fields from admin.py and models.py
Auwate Mar 26, 2024
b4bbfa2
CHANGES - Sorting | Added action_notes
Auwate Mar 27, 2024
e2d7f61
CHANGES:
Auwate Mar 27, 2024
ef84c01
CHANGES:
Auwate Mar 27, 2024
03c4839
CHANGES:
Auwate Mar 27, 2024
f71c667
Minor Change
Auwate Mar 27, 2024
c9c6f46
Minor changes
Auwate Mar 27, 2024
7d81895
Added functionality:
Auwate Mar 27, 2024
4d52c6b
Minor change
Auwate Mar 27, 2024
e66c374
Edited labels to show what each mean.
Auwate Mar 27, 2024
68799b3
CHANGE
Auwate Mar 27, 2024
4e9a385
MAJOR CHANGE:
Auwate Mar 27, 2024
02ec4fe
Updates to background color
Auwate Mar 27, 2024
67e6e94
Removing temporary development to start merging into production.
Auwate Apr 1, 2024
b505509
Added unit test for custom command.
Auwate Apr 1, 2024
e23b272
TEMPORARY COMMIT: TRYING DOCKER TESTING
Auwate Apr 1, 2024
62d1f66
Removing docker-compose test command on startup.
Auwate Apr 1, 2024
43dca1b
MAJOR COMMIT:
Auwate Apr 3, 2024
2c05c5c
Updated documentation
Auwate Apr 3, 2024
c0182a8
Merge branch 'development'
Auwate Apr 3, 2024
9461a1b
Update Dockerfile
Auwate Apr 3, 2024
1c91ea6
COMMIT: Updated logging
Auwate Apr 8, 2024
9f23c8e
Testing Commit: Turning off SESSION_COOKIE_SECURE
Auwate Apr 8, 2024
a9af0e8
Turned SESSION_COOKIE to True
Auwate Apr 8, 2024
675fdcb
Merge branch 'merging'
Auwate Apr 8, 2024
b51d98c
Merge branch 'master' of https://github.com/Auwate/Services-Status
Auwate Apr 8, 2024
98fde16
MAJOR COMMIT: Reducing fluff in merge request.
Auwate Apr 9, 2024
13ea9c0
COMMIT: Fault tolerance by making sure an AttributeError does not occ…
Auwate Apr 9, 2024
2d93cb8
COMMIT:
Auwate Apr 9, 2024
824d671
Update settings-dev.py
Auwate Apr 9, 2024
c8d00ff
Update settings-dev.py
Auwate Apr 9, 2024
e238e57
Update settings-dev.py
Auwate Apr 9, 2024
75f90f0
Align with master repo
Auwate Apr 9, 2024
0f91357
Update services_status.html
Auwate Apr 9, 2024
8838a68
Update test_models.py
Auwate Apr 9, 2024
0da35f2
Update test_models.py
Auwate Apr 9, 2024
2d6b081
Update test_models.py
Auwate Apr 9, 2024
07a3c28
- Commit:
Auwate Apr 9, 2024
0f242f7
Update Dockerfile
Auwate Apr 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions DEV_TIPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Reading Markdown Files

To read Markdown files (.md) in VS Code, press Ctrl+Shift+V for Markdown preview.

# Required Prerequisites

- Python
- HTML/CSS
- Django
- Docker
- SQL
- Linux/Unix

# Django

Documentation can be found at https://docs.djangoproject.com/en/3.0/

## Testing

In case of errors, turn on debug in settings-dev.py or by using the following command:
```
sed -i "s/DEBUG = False/DEBUG = True/g" /opt/Services-Status/ServiceStatus/settings.py
```

## HTTPS to HTTP

Django uses HTTP in testing environments, so make sure to turn SESSION_COOKIE_SECURE to False. You can do that in settings-dev.py, or by using the following command:
```
sed -i "s/SESSION_COOKIE_SECURE = True/SESSION_COOKIE_SECURE = False/g" /opt/Services-Status/ServiceStatus/settings.py
```

# Unix/Linux Environment

The application is built for Unix/Linux development, so locally developing the application on other operating systems is **not** recommended. Ask a network engineer or your lead developer to help give you access to the remote server being used to test.

Unix/Linux documentation can be found at https://docs.kernel.org/, or by searching up common commands used.

# Docker

Documentation can be found at https://docs.docker.com/

This application uses docker-compose to build and run, so before using any commands you must be in the deploy folder.

## Common Docker commands
```
docker-compose build
```
This will run the build script, pulling the data from the 3 Docker files found in the folder.
```
docker-compose up
```
This will run the docker container in your terminal.
```
docker-compose up -d
```
This will run the docker container in the background. This is especially useful if you want to debug or enter into the shell.
```
docker-compose kill
```
This will terminate the running container so you do not consume excess resources. This is especially important if you run **docker-compose up -d** or if you run docker-compose up and disconnect from the terminal.
```
docker exec -it <container_name> /bin/bash
```
This will connect you into the container's bash terminal.
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Services-Status

The Services-Status repository is used to power the status page used by network engineers at CIARA (https://status.amlight.net/) It uses Django + jQuery to run the web server, supplying templates based on what view you are currently in.

For documentation, on tech used and useful tips, check DEV_TIPS.md

## Recent Changes

- Tickets are now ordered in descending order by the *begin* field (Newest first)
- Tickets in the main view now contain a latest_update field, which uses the action_description found in TicketLogs.
- Custom command added to immediately populate the database with Status objects, if they are not there already.
- Unit tests are being rolled out to test new features.
- Documentation is being rolled out on a daily basis.

## Unit Testing

Testing is implemented by running the following command:
```
python3 manage.py test status.tests --settings=ServiceStatus.settings-test
```
(If python3 does not work, use **python**)

### Development

To create more tests, navigate to the status/tests directory. Each test will be run since they start with *test_*, so write your tests under the test file that covers your domain. For example, if you're testing a new command, do it under *test_commands*.

## Logging Driver

For quicker development and testing, the logging driver was commented out from docker-compose.yml. When pushing to production remember to uncomment this.

## Deployment Methodology

The Service Status application uses Docker to gather its dependencies and deploy onto a remote server. It uses a .yml script to build, so this application uses docker-compose.

To **test**, make sure to turn Debug = True and SESSION_COOKIE_COOKIE = False. You can find more information on how to do this in the DEV_TIPS.md file.

## Unix (remote environment)

The services-status application was created to run on a Unix environment, which is the environment used by the remote server. Currently, development is taking place on a virtual machine, so ask the networking team to help you gain access to the current VM the developers are using, or to create your own.
3 changes: 2 additions & 1 deletion ServiceStatus/settings-dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
EMAIL_HOST_PASSWORD = 'XXXSMTPPASSXXX'
EMAIL_PORT = 587

# TURNED OFF FOR DEVELOPMENT. TURN ON FOR PRODUCTION.
SESSION_COOKIE_SECURE = True

CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
164 changes: 164 additions & 0 deletions ServiceStatus/settings-test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
SPECIAL FILE

This settings.py file will be used strictly for testing. The
main difference between this one and settings-dev.py is the database used. This
one uses local memory and SQLite, rather than a remote docker container that
settings-dev.py uses.

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

from django.core.mail.utils import DNS_NAME

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
# For Django 1.10 and above you can use:
# from django.core.management.utils import get_random_secret_key
# get_random_secret_key()
SECRET_KEY = 'XXXSECRETKEYXXX'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []

# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'status.apps.StatusConfig',
'django_extensions',
'tinymce',
'django_admin_listfilter_dropdown',
'colorfield',
'ckeditor',
'ckeditor_uploader',
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'ServiceStatus.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

WSGI_APPLICATION = 'ServiceStatus.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases

DATABASES = {
'default':{
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:'
}
}

# Password validation
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'America/New_York'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/

STATIC_URL = '/static/'

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))

STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')

STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)

GRAPH_MODELS = {
'all_applications': True,
'group_models': True,
}

CKEDITOR_BASEPATH = "/static/ckeditor/ckeditor/"

CKEDITOR_UPLOAD_PATH = "/uploads/"

SMTP_HOST = "XXXSMTPHOSTXXX"
SMTP_PORT = 587
SMTP_USER = "XXXSMTPUSERXXX"
SMTP_PASS = "XXXSMTPPASSXXX"

# SMTP Configuration
DNS_NAME._fqdn = 'localhost'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = 'XXXSMTPHOSTXXX'
DEFAULT_FROM_EMAIL = 'XXXSMTPUSERXXX'
EMAIL_HOST_USER = 'XXXSMTPUSERXXX'
EMAIL_HOST_PASSWORD = 'XXXSMTPPASSXXX'
EMAIL_PORT = 587

# TURNED ON FOR DEVELOPMENT. TURN OFF FOR PRODUCTION.
SESSION_COOKIE_SECURE = False

CSRF_COOKIE_HTTPONLY = True
1 change: 1 addition & 0 deletions deploy/docker-startup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ cd /opt/Services-Status
sleep 30
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py create_initial_objects

/etc/init.d/nginx start
gunicorn --access-logfile - --workers 4 --user www-data --group www-data --bind 127.0.0.1:8800 --access-logformat '%(h)s/%({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"' ServiceStatus.wsgi:application
2 changes: 1 addition & 1 deletion status/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class TicketAdmin(admin.ModelAdmin):
DropdownFilter),
('sub_service',
RelatedDropdownFilter))
ordering = ['end']
ordering = ['-begin']

actions = [notify_users]

Expand Down
4 changes: 4 additions & 0 deletions status/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ class TicketForm(forms.ModelForm):
class Meta:
model = Ticket
fields = '__all__'
labels = {
'begin' : "Begin - Use UTC",
'end' : "End - Use UTC",
}

def __init__(self, *args, **kwargs):

Expand Down
22 changes: 22 additions & 0 deletions status/management/commands/create_initial_objects.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from django.core.management.base import BaseCommand
from status.models import Status

class Command(BaseCommand):

help = 'Creates the initial objects required to start the service-status application'

def handle(self, *args, **options):

if Status.objects.count() > 0:
return

initial_objects = [
{"tag":"Alert", "color_name": "Orange", "color_hex":"#FC810D", "class_design": "fas fa-exclamation-circle"},
{"tag":"In Process", "color_name": "Yellow", "color_hex":"#DBBF07", "class_design": "fas fa-tools"},
{"tag":"No Issues", "color_name": "Green", "color_hex":"#0AC739", "class_design": "fas fa-check-circle"},
{"tag":"Outage", "color_name": "Red", "color_hex":"#F00004", "class_design": "fas fa-times-circle"},
{"tag":"Planned", "color_name": "Blue", "color_hex":"#041DBF", "class_design": "far fa-calendar-alt"}
]

for data_objects in initial_objects:
Status.objects.create(**data_objects)
8 changes: 8 additions & 0 deletions status/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ class Ticket(models.Model):
null=True, default=3, verbose_name='Status')
begin = models.DateTimeField()
end = models.DateTimeField(null=True, blank=True)

action_description = RichTextField()
action_notes = RichTextField(blank=True, null=True)

Expand Down Expand Up @@ -336,6 +337,13 @@ class TicketLog(models.Model):
action_date = models.DateTimeField()
action_notes = RichTextField(blank=True, null=True, verbose_name='Notes')

def description (self):
if self.action_notes is not None:
return format_html(self.action_notes)
return self.action_notes

description.allow_tags = True

def __str__(self):
queryset_list = []
for sub_service in self.ticket.sub_service.all():
Expand Down
7 changes: 6 additions & 1 deletion status/templates/services_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h3 class="bold">Recent Events</h3>
<p><span class="bold">Status: </span>{{ ticket.status.tag }}</p>

{% if ticket.status.tag == "Planned" %}
<p><span class="bold">Action Date: </span>{{ ticket.begin }}</p>
<p><span class="bold">Action Date: </span>{{ ticket.begin }} UTC </p>

{% if ticket.end|localtime|timesince >= "1 min" %}
<p><span class="bold">Current Status Information: </span>Completed</p>
Expand All @@ -53,6 +53,11 @@ <h3 class="bold">Recent Events</h3>

<p id="ticket_description">{{ ticket.action_description | safe }}</p>
<!-- Description of the ticket -->

{% if ticket.latest_action_notes %}
<p><span class="bold">Latest Update: </span>{{ticket.latest_action_date}} | UTC {{ticket.latest_action_notes}}</p>
{% endif %}

</a>
</div>

Expand Down
Loading