Skip to content

Commit 5997a4f

Browse files
authored
Merge pull request #31 from jtdub/whois
Whois
2 parents f045bb9 + d06a524 commit 5997a4f

File tree

21 files changed

+193
-39
lines changed

21 files changed

+193
-39
lines changed

development/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ COPY poetry.lock .
1414

1515
# hadolint ignore=DL3008
1616
RUN apt-get update && \
17-
apt-get install -y --no-install-recommends nmap iputils-ping traceroute curl mariadb-client libmariadb-dev gcc && \
17+
apt-get install -y --no-install-recommends nmap iputils-ping traceroute curl mariadb-client libmariadb-dev gcc whois && \
1818
apt-get autoremove -y && \
1919
apt-get clean all && \
2020
rm -rf /var/lib/apt/lists/*

netopsio/core/admin.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
"""Register core models in admin panel."""
22

3-
from django.contrib import admin
4-
53
from core.models import RequestLog
4+
from django.contrib import admin
65

76

87
class RequestLogAdmin(admin.ModelAdmin):

netopsio/core/api/serializers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
"""Core App and Worker Serializers."""
2+
from core import models
23
from django_celery_results.models import TaskResult
34
from rest_framework import serializers
45

5-
from core import models
6-
76

87
class TaskResultSerializer(serializers.HyperlinkedModelSerializer):
98
"""TaskResult Serializer."""

netopsio/core/api/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
"""Netops.io core api urls."""
22

3-
from rest_framework.routers import DefaultRouter
4-
53
from core.api import views
4+
from rest_framework.routers import DefaultRouter
65

76
router = DefaultRouter()
87
router.register(r"tasks", views.TaskResultViewSet)
98
router.register(r"request-logs", views.RequestLogViewSet, basename="requestlog")
109
router.register(r"ping", views.PingViewSet, basename="ping")
1110
router.register(r"traceroute", views.TraceRouteViewSet, basename="traceroute")
1211
router.register(r"nmap", views.NmapViewSet, basename="nmap")
12+
router.register(r"whois", views.WhoisViewSet, basename="whois")

netopsio/core/api/views.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
"""Netops.io core api views."""
22

3+
from core import models, tasks
4+
from core.api import serializers
35
from django_celery_results.models import TaskResult
46
from drf_yasg import openapi
57
from drf_yasg.utils import swagger_auto_schema
68
from rest_framework import viewsets
79
from rest_framework.response import Response
810

9-
from core import models, tasks
10-
from core.api import serializers
1111
from netopsio.utilities import get_ip_address
1212

1313

@@ -90,3 +90,24 @@ def create(self, request, host=None):
9090
data = models.TaskModel(task_id=task.task_id)
9191
serializer = serializers.TaskSerializer(data, context={"request": request})
9292
return Response(serializer.data)
93+
94+
95+
class WhoisViewSet(viewsets.ViewSet):
96+
"""Whois Viewset."""
97+
98+
@swagger_auto_schema(
99+
request_body=openapi.Schema(
100+
type=openapi.TYPE_OBJECT,
101+
properties={
102+
"host": openapi.Schema(
103+
type=openapi.TYPE_STRING, description="Whois a domain or host."
104+
),
105+
},
106+
)
107+
) # pylint: disable=no-self-use
108+
def create(self, request, host):
109+
"""whois a host."""
110+
task = tasks.whois.delay(host=host)
111+
data = models.TaskModel(task_id=task.task_id)
112+
serializer = serializers.TaskSerializer(data, context={"request": request})
113+
return Response(serializer.data)

netopsio/core/forms.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""Netops.io core app forms."""
2+
3+
from django import forms
4+
5+
6+
class WhoisForm(forms.Form):
7+
"""Whois form."""
8+
9+
host = forms.CharField(label="domain or ip address", max_length=256)

netopsio/core/tasks.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import subprocess
33

44
from celery import shared_task
5-
65
from core.models import RequestLog
76

87

@@ -33,3 +32,12 @@ def nmap(host: str) -> str:
3332
data = RequestLog(ip=host, result=task.stdout.decode("utf-8"), app="nmap")
3433
data.save()
3534
return task.stdout.decode("utf-8")
35+
36+
37+
@shared_task
38+
def whois(host: str) -> str:
39+
"""Whois host worker."""
40+
task = subprocess.run(["whois", host], capture_output=True, check=True)
41+
data = RequestLog(ip=host, result=task.stdout.decode("utf-8"), app="whois")
42+
data.save()
43+
return task.stdout.decode("utf-8")

netopsio/core/templates/core/task.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<tbody>
1010
<tr>
1111
<td>{{ status }}</td>
12-
<td><a href="/tasks/{{ id }}/">{{ host }}</a></td>
12+
<td><a href="{% url 'tasks' %}{{ id }}/">{{ host }}</a></td>
1313
</tr>
1414
</tbody>
1515
</table>

netopsio/core/templates/core/tasks.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<tbody>
1212
{% for task in results %}
1313
<tr>
14-
<th scope="row"><a href="/tasks/{{ task.task_id }}">{{ task.task_id }}</a></th>
14+
<th scope="row"><a href="{% url 'tasks' %}{{ task.task_id }}">{{ task.task_id }}</a></th>
1515
<td>{{ task.task_name }}</td>
1616
<td>{{ task.status }}</td>
1717
<td>{{ task.task_kwargs }}</td>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% extends "base.html" %}
2+
{% block content %}
3+
{% load crispy_forms_tags %}
4+
<form action="{% url 'whois' %}" method="post">
5+
{% csrf_token %}
6+
{{ form|crispy }}
7+
<input type="submit" value="Submit" class="btn btn-primary">
8+
</form>
9+
{% endblock %}

netopsio/core/tests/test_api.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
"""Core api tests."""
2+
from core.api import views
23
from django.test import TestCase
34
from rest_framework.test import APIRequestFactory
45

5-
from core.api import views
6-
76

87
class CoreApiTestCase(TestCase):
98
def setUp(self):
@@ -41,3 +40,12 @@ def test_nmap_api(self):
4140
)
4241
response = self.nmap.create(request)
4342
self.assertEqual(response.status_code, 200)
43+
44+
def test_whois_api(self):
45+
request = self.factory.post(
46+
"/api/v1/whois/",
47+
self.host,
48+
content_type=self.content_type,
49+
)
50+
response = self.nmap.create(request)
51+
self.assertEqual(response.status_code, 200)

netopsio/core/tests/test_models.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"Core app tests."
2-
from django.test import TestCase
3-
42
from core.models import RequestLog
3+
from django.test import TestCase
54

65

76
class RequestLogTestCase(TestCase):

netopsio/core/tests/test_tasks.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
"""Core tasks tests."""
22

33

4-
from django.test import TestCase
5-
64
from core import tasks
5+
from django.test import TestCase
76

87

98
class TasksTestCase(TestCase):
@@ -21,3 +20,7 @@ def test_traceroute_task(self):
2120
def test_nmap_task(self):
2221
nmap = tasks.nmap.delay(host=self.host)
2322
self.assertIn(nmap.status, ("PENDING", "STARTED", "SUCCESS"))
23+
24+
def test_whois_task(self):
25+
whois = tasks.whois.delay(host=self.host)
26+
self.assertIn(whois.status, ("PENDING", "STARTED", "SUCCESS"))

netopsio/core/tests/test_views.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,38 @@ def test_index_view(self):
1010
response = self.client.get("/")
1111
self.assertTemplateUsed(response, "core/base.html")
1212
self.assertEqual(response.status_code, 200)
13+
14+
def test_tasks_view(self):
15+
"""Test the tasks view."""
16+
response = self.client.get("/tasks/")
17+
self.assertTemplateUsed(response, "core/tasks.html")
18+
self.assertEqual(response.status_code, 200)
19+
20+
def test_task_details_view(self):
21+
"""Test the task details view."""
22+
response = self.client.get("/tasks/21f58fbc-e8e5-4f72-a783-47300197e7da/")
23+
self.assertEqual(response.status_code, 404)
24+
25+
def test_ping_view(self):
26+
"""Test the ping view."""
27+
response = self.client.get("/ping/")
28+
self.assertTemplateUsed(response, "core/task.html")
29+
self.assertEqual(response.status_code, 200)
30+
31+
def test_traceroute_view(self):
32+
"""Test the traceroute view."""
33+
response = self.client.get("/traceroute/")
34+
self.assertTemplateUsed(response, "core/task.html")
35+
self.assertEqual(response.status_code, 200)
36+
37+
def test_nmap_view(self):
38+
"""Test the nmap view."""
39+
response = self.client.get("/nmap/")
40+
self.assertTemplateUsed(response, "core/task.html")
41+
self.assertEqual(response.status_code, 200)
42+
43+
def test_whois_view(self):
44+
"""Test the ping view."""
45+
response = self.client.get("/whois/")
46+
self.assertTemplateUsed(response, "core/whois.html")
47+
self.assertEqual(response.status_code, 200)

netopsio/core/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"Core app urls."
2-
from django.urls import path
3-
42
from core import views
3+
from django.urls import path
54

65
urlpatterns = [
76
path("", views.index, name="core-index"),
@@ -10,4 +9,5 @@
109
path("ping/", views.ping, name="ping"),
1110
path("traceroute/", views.traceroute, name="traceroute"),
1211
path("nmap/", views.nmap, name="nmap"),
12+
path("whois/", views.whois, name="whois"),
1313
]

netopsio/core/views.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
"Core app views."
2+
from core import forms, tasks
23
from django.http import HttpResponse
34
from django.shortcuts import get_object_or_404
45
from django.template import loader
56
from django_celery_results.models import TaskResult
67

7-
from core import tasks
88
from netopsio.utilities import get_ip_address
99

1010

@@ -57,3 +57,25 @@ def nmap(request):
5757
template = loader.get_template("core/task.html")
5858
context = {"host": host, "status": task.status, "id": task, "title": "Nmap"}
5959
return HttpResponse(template.render(context, request))
60+
61+
62+
def whois(request):
63+
"""Whois view."""
64+
if request.method == "POST":
65+
form = forms.WhoisForm(request.POST)
66+
67+
if form.is_valid():
68+
host = form.cleaned_data["host"]
69+
task = tasks.whois.delay(host)
70+
template = loader.get_template("core/task.html")
71+
context = {
72+
"host": host,
73+
"status": task.status,
74+
"id": task,
75+
"title": "Whois",
76+
}
77+
return HttpResponse(template.render(context, request))
78+
79+
context = {"form": forms.WhoisForm(), "title": "Whois"}
80+
template = loader.get_template("core/whois.html")
81+
return HttpResponse(template.render(context, request))

netopsio/netopsio/settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
"rest_framework",
4242
"drf_yasg",
4343
"django_celery_results",
44+
"crispy_forms",
45+
"crispy_bootstrap5",
4446
"core",
4547
]
4648

@@ -148,3 +150,6 @@
148150
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
149151
"PAGE_SIZE": 10,
150152
}
153+
154+
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
155+
CRISPY_TEMPLATE_PACK = "bootstrap5"

netopsio/netopsio/urls.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
1. Import the include() function: from django.urls import include, path
1414
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
1515
"""
16+
from core.api.urls import router
1617
from django.contrib import admin
1718
from django.urls import include, path, re_path
1819
from drf_yasg import openapi
1920
from drf_yasg.views import get_schema_view
2021
from rest_framework import permissions
2122

22-
from core.api.urls import router
23-
2423
schema_view = get_schema_view( # pylint: disable=invalid-name
2524
openapi.Info(
2625
title="NetOps.io API",

netopsio/templates/base.html

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,30 @@
1313
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
1414
<nav class="navbar navbar-expand-lg navbar-light bg-light">
1515
<div class="container-fluid">
16-
<a class="navbar-brand" href="#">NetOps.io</a>
16+
<a class="navbar-brand" href="{% url 'core-index' %}">NetOps.io</a>
1717
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
1818
<span class="navbar-toggler-icon"></span>
1919
</button>
20+
21+
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavDarkDropdown"
22+
aria-controls="navbarNavDarkDropdown" aria-expanded="false" aria-label="Toggle navigation">
23+
<span class="navbar-toggler-icon"></span>
24+
</button>
25+
2026
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
2127
<div class="navbar-nav">
22-
<a class="nav-link" href="/">Home</a>
23-
<a class="nav-link" href="/tasks/">Task Results</a>
24-
<a class="nav-link" href="/ping/">Ping</a>
25-
<a class="nav-link" href="/traceroute/">Traceroute</a>
26-
<a class="nav-link" href="/nmap/">Nmap</a>
28+
<a class="nav-link" href="{% url 'tasks' %}">Task Results</a>
29+
<li class="nav-item dropdown">
30+
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
31+
Applications
32+
</a>
33+
<ul class="dropdown-menu dropdown-menu">
34+
<li><a class="nav-link" href="{% url 'ping' %}">Ping</a></li>
35+
<li><a class="nav-link" href="{% url 'traceroute' %}">Traceroute</a></li>
36+
<li><a class="nav-link" href="{% url 'nmap' %}">Nmap</a></li>
37+
<li><a class="nav-link" href="{% url 'whois' %}">Whois</a></li>
38+
</ul>
39+
</li>
2740
</div>
2841
</div>
2942
</div>

0 commit comments

Comments
 (0)