• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djangoaddicts / django-hostutils / 5305512247

pending completion
5305512247

push

github-actions

davidslusser
adding isort; adding additional badges to readme

60 of 60 branches covered (100.0%)

Branch coverage included in aggregate %.

247 of 247 relevant lines covered (100.0%)

1.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/src/djangoaddicts/hostutils/views/htmx.py
1
import datetime
1✔
2

3
import psutil
1✔
4
from django.http import HttpResponse
1✔
5
from django.shortcuts import render
1✔
6
from django.template import loader
1✔
7
from django.views.generic import View
1✔
8
from handyhelpers.views.htmx import BuildBootstrapModalView
1✔
9

10
# import forms
11
from djangoaddicts.hostutils.forms import HostProcessFilterForm
1✔
12

13

14
class GetHostCpuStats(BuildBootstrapModalView):
1✔
15
    """Get statistics for a given CPU"""
16

17
    modal_button_close = None
1✔
18
    modal_button_submit = "Close"
1✔
19
    modal_size = "modal-lg"
1✔
20
    modal_title = "CPU Details"
1✔
21

22
    def get(self, request, *args, **kwargs):
1✔
23
        context = {}
1✔
24
        self.modal_subtitle = kwargs["cpu"]
1✔
25
        try:
1✔
26
            cpu = kwargs["cpu"]
1✔
27
            context = {
1✔
28
                "time": psutil.cpu_times(percpu=True)[cpu],
29
                "time_percent": psutil.cpu_times_percent(percpu=True)[cpu],
30
                "frequency": psutil.cpu_freq(percpu=True)[cpu],
31
            }
32
        except IndexError:
1✔
33
            return HttpResponse("Invalid request", status=400)
1✔
34
        self.modal_body = loader.render_to_string("hostutils/bs5/htmx/get_cpu_stats.htm", context=context)
1✔
35
        return super().get(request, *args, **kwargs)
1✔
36

37

38
class GetHostNetworkStats(BuildBootstrapModalView):
1✔
39
    """Get statistics for a given network interface"""
40

41
    modal_button_close = None
1✔
42
    modal_button_submit = "Close"
1✔
43
    modal_size = "modal-lg"
1✔
44
    modal_title = "Network Interface Details"
1✔
45

46
    def get(self, request, *args, **kwargs):
1✔
47
        context = {}
1✔
48
        self.modal_subtitle = kwargs["interface"]
1✔
49
        try:
1✔
50
            context["data"] = psutil.net_if_stats()[kwargs["interface"]]
1✔
51
        except KeyError:
1✔
52
            return HttpResponse("Invalid request", status=400)
1✔
53
        self.modal_body = loader.render_to_string("hostutils/bs5/htmx/get_interface_stats.htm", context=context)
1✔
54
        return super().get(request, *args, **kwargs)
1✔
55

56

57
class GetHostParitionStats(BuildBootstrapModalView):
1✔
58
    """Get statistics for a given disk partition"""
59

60
    modal_button_close = None
1✔
61
    modal_button_submit = "Close"
1✔
62
    modal_title = "Partition Details"
1✔
63

64
    def get(self, request, *args, **kwargs):
1✔
65
        context = {}
1✔
66
        part = request.GET.get("part", None)
1✔
67
        self.modal_subtitle = part
1✔
68
        try:
1✔
69
            context["data"] = psutil.disk_usage(part)
1✔
70
        except FileNotFoundError:
1✔
71
            return HttpResponse("Invalid request", status=400)
1✔
72
        self.modal_body = loader.render_to_string("hostutils/bs5/htmx/get_partition_stats.htm", context=context)
1✔
73
        return super().get(request, *args, **kwargs)
1✔
74

75

76
class GetHostProcesses(View):
1✔
77
    """Get host processes"""
78

79
    @staticmethod
1✔
80
    def get_process_count(process_list: list, status: str) -> int:
1✔
81
        """get a count of processes for a given status
82

83
        Args:
84
            process_list (list): list of processes as returned from psutil.process_iter()
85
            status (str): name of process status to count
86

87
        Returns:
88
            int: number of processes of 'status'
89
        """
90
        count = 0
1✔
91
        for process in process_list:
1✔
92
            try:
1✔
93
                if process.status() == status:
1✔
94
                    count += 1
1✔
95
            except psutil.NoSuchProcess:
1✔
96
                continue
1✔
97
        return count
1✔
98

99
    def get(self, request):
1✔
100
        """Get host prcesses"""
101
        context = {}
1✔
102
        process_list = list(psutil.process_iter())
1✔
103
        filter_form = HostProcessFilterForm(request.GET or None)
1✔
104
        context["counts"] = {
1✔
105
            "running": self.get_process_count(process_list, "running"),
106
            "sleeping": self.get_process_count(process_list, "sleeping"),
107
            "idle": self.get_process_count(process_list, "idle"),
108
            "stopped": self.get_process_count(process_list, "stopped"),
109
            "zombie": self.get_process_count(process_list, "zombie"),
110
            "dead": self.get_process_count(process_list, "dead"),
111
        }
112

113
        if request.GET.dict().get("clear", None):
1✔
114
            context["clear_filter"] = False
1✔
115

116
        else:
117
            if filter_form.is_valid():
1✔
118
                context["clear_filter"] = True
1✔
119

120
                if filter_form.cleaned_data.get("status", None):
1✔
121
                    filtered_process_list = []
1✔
122
                    for i in process_list:
1✔
123
                        if i.status() in filter_form.cleaned_data["status"]:
1✔
124
                            filtered_process_list.append(i)
1✔
125
                    process_list = filtered_process_list
1✔
126

127
                if filter_form.cleaned_data.get("created_at__gte", None):
1✔
128
                    filtered_process_list = []
1✔
129
                    for i in process_list:
1✔
130
                        if i.create_time() > filter_form.cleaned_data["created_at__gte"].timestamp():
1✔
131
                            filtered_process_list.append(i)
1✔
132
                    process_list = filtered_process_list
1✔
133
                if filter_form.cleaned_data.get("created_at__lte", None):
1✔
134
                    filtered_process_list = []
1✔
135
                    for i in process_list:
1✔
136
                        if i.create_time() < filter_form.cleaned_data["created_at__lte"].timestamp():
1✔
137
                            filtered_process_list.append(i)
1✔
138
                    process_list = filtered_process_list
1✔
139

140
        context["process_list"] = process_list
1✔
141
        context["title"] = "Host Processes"
1✔
142
        context["now"] = datetime.datetime.now()
1✔
143
        context["subtitle"] = psutil.os.uname()[1]
1✔
144
        filter_form = {}
1✔
145
        filter_form["form"] = HostProcessFilterForm(request.GET or None)
1✔
146
        filter_form["modal_name"] = "filter_processes"
1✔
147
        filter_form["modal_size"] = "modal-lg"
1✔
148
        filter_form["modal_title"] = "Filter Host Processes"
1✔
149
        filter_form["hx_method"] = "hx-get"
1✔
150
        filter_form["hx_url"] = "/hostutils/get_host_processes"
1✔
151
        filter_form["hx_target"] = "id_process_list_container"
1✔
152
        filter_form["method"] = "GET"
1✔
153
        filter_form["action"] = "Filter"
1✔
154
        context["filter_form"] = filter_form
1✔
155
        return render(request, template_name="hostutils/bs5/snippets/host_process_card_swap.htm", context=context)
1✔
156

157

158
class GetHostProcessStats(BuildBootstrapModalView):
1✔
159
    """Get statistics for a given process"""
160

161
    modal_button_close = None
1✔
162
    modal_button_submit = "Close"
1✔
163
    modal_size = "modal-lg"
1✔
164
    modal_title = "Process Details"
1✔
165

166
    def get(self, request, *args, **kwargs):
1✔
167
        context = {}
1✔
168
        self.modal_subtitle = kwargs["pid"]
1✔
169
        try:
1✔
170
            data = psutil.Process(kwargs["pid"])
1✔
171
            context = {
1✔
172
                "pid": data.pid,
173
                "ppid": data.ppid(),
174
                "name": data.name(),
175
                "status": data.status(),
176
                "create_time": data.create_time(),
177
                "username": data.username(),
178
                "cmdline": data.cmdline(),
179
                "cpu_num": data.cpu_num(),
180
                "cpu_percent": data.cpu_percent(),
181
                "memory_percent": data.memory_percent(),
182
                "num_threads": data.num_threads(),
183
                "threads": data.threads(),
184
            }
185
            context["cwd"] = data.cwd()
1✔
186
            context["exe"] = data.exe()
1✔
187
        except psutil.AccessDenied:
1✔
188
            pass
1✔
189
        except psutil.NoSuchProcess:
1✔
190
            pass
1✔
191
        self.modal_body = loader.render_to_string("hostutils/bs5/htmx/get_process_stats.htm", context=context)
1✔
192
        return super().get(request, *args, **kwargs)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc