patchman 2.0.17__tar.gz → 3.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. {patchman-2.0.17 → patchman-3.0.0}/INSTALL.md +29 -17
  2. {patchman-2.0.17 → patchman-3.0.0}/MANIFEST.in +1 -0
  3. {patchman-2.0.17 → patchman-3.0.0}/PKG-INFO +9 -8
  4. patchman-3.0.0/VERSION.txt +1 -0
  5. {patchman-2.0.17 → patchman-3.0.0}/etc/patchman/local_settings.py +4 -1
  6. {patchman-2.0.17 → patchman-3.0.0}/hosts/models.py +30 -4
  7. {patchman-2.0.17 → patchman-3.0.0}/hosts/templates/hosts/host_detail.html +9 -0
  8. patchman-3.0.0/modules/admin.py +20 -0
  9. patchman-3.0.0/modules/apps.py +21 -0
  10. patchman-3.0.0/modules/managers.py +22 -0
  11. patchman-3.0.0/modules/models.py +44 -0
  12. patchman-3.0.0/modules/serializers.py +25 -0
  13. patchman-3.0.0/modules/templates/modules/module_detail.html +69 -0
  14. patchman-3.0.0/modules/templates/modules/module_list.html +7 -0
  15. patchman-3.0.0/modules/templates/modules/module_table.html +23 -0
  16. patchman-3.0.0/modules/urls.py +26 -0
  17. patchman-3.0.0/modules/views.py +74 -0
  18. {patchman-2.0.17 → patchman-3.0.0}/packages/utils.py +23 -1
  19. {patchman-2.0.17 → patchman-3.0.0}/patchman/settings.py +3 -0
  20. {patchman-2.0.17 → patchman-3.0.0}/patchman/urls.py +1 -0
  21. {patchman-2.0.17 → patchman-3.0.0}/patchman.egg-info/PKG-INFO +9 -8
  22. {patchman-2.0.17 → patchman-3.0.0}/patchman.egg-info/SOURCES.txt +11 -0
  23. {patchman-2.0.17 → patchman-3.0.0}/patchman.egg-info/requires.txt +8 -7
  24. {patchman-2.0.17 → patchman-3.0.0}/patchman.egg-info/top_level.txt +1 -0
  25. {patchman-2.0.17 → patchman-3.0.0}/reports/models.py +16 -3
  26. patchman-3.0.0/reports/templates/reports/report.txt +29 -0
  27. {patchman-2.0.17 → patchman-3.0.0}/reports/templates/reports/report_detail.html +17 -0
  28. {patchman-2.0.17 → patchman-3.0.0}/reports/utils.py +101 -3
  29. {patchman-2.0.17 → patchman-3.0.0}/reports/views.py +8 -4
  30. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/repo_detail.html +9 -0
  31. {patchman-2.0.17 → patchman-3.0.0}/repos/utils.py +124 -18
  32. {patchman-2.0.17 → patchman-3.0.0}/requirements.txt +8 -7
  33. {patchman-2.0.17 → patchman-3.0.0}/sbin/patchman +20 -1
  34. {patchman-2.0.17 → patchman-3.0.0}/scripts/rpm-post-install.sh +4 -3
  35. {patchman-2.0.17 → patchman-3.0.0}/setup.cfg +4 -3
  36. patchman-3.0.0/util/templatetags/__init__.py +0 -0
  37. patchman-2.0.17/VERSION.txt +0 -1
  38. patchman-2.0.17/reports/templates/reports/report.txt +0 -16
  39. {patchman-2.0.17 → patchman-3.0.0}/AUTHORS +0 -0
  40. {patchman-2.0.17 → patchman-3.0.0}/COPYING +0 -0
  41. {patchman-2.0.17 → patchman-3.0.0}/README.md +0 -0
  42. {patchman-2.0.17 → patchman-3.0.0}/arch/__init__.py +0 -0
  43. {patchman-2.0.17 → patchman-3.0.0}/arch/admin.py +0 -0
  44. {patchman-2.0.17 → patchman-3.0.0}/arch/apps.py +0 -0
  45. {patchman-2.0.17 → patchman-3.0.0}/arch/models.py +0 -0
  46. {patchman-2.0.17 → patchman-3.0.0}/arch/serializers.py +0 -0
  47. {patchman-2.0.17 → patchman-3.0.0}/arch/views.py +0 -0
  48. {patchman-2.0.17 → patchman-3.0.0}/domains/__init__.py +0 -0
  49. {patchman-2.0.17 → patchman-3.0.0}/domains/admin.py +0 -0
  50. {patchman-2.0.17 → patchman-3.0.0}/domains/apps.py +0 -0
  51. {patchman-2.0.17 → patchman-3.0.0}/domains/models.py +0 -0
  52. {patchman-2.0.17 → patchman-3.0.0}/domains/serializers.py +0 -0
  53. {patchman-2.0.17 → patchman-3.0.0}/domains/views.py +0 -0
  54. {patchman-2.0.17 → patchman-3.0.0}/etc/patchman/apache.conf.example +0 -0
  55. {patchman-2.0.17 → patchman-3.0.0}/hosts/__init__.py +0 -0
  56. {patchman-2.0.17 → patchman-3.0.0}/hosts/admin.py +0 -0
  57. {patchman-2.0.17 → patchman-3.0.0}/hosts/apps.py +0 -0
  58. {patchman-2.0.17 → patchman-3.0.0}/hosts/forms.py +0 -0
  59. {patchman-2.0.17 → patchman-3.0.0}/hosts/managers.py +0 -0
  60. {patchman-2.0.17 → patchman-3.0.0}/hosts/serializers.py +0 -0
  61. {patchman-2.0.17 → patchman-3.0.0}/hosts/templates/hosts/host_delete.html +0 -0
  62. {patchman-2.0.17 → patchman-3.0.0}/hosts/templates/hosts/host_edit.html +0 -0
  63. {patchman-2.0.17 → patchman-3.0.0}/hosts/templates/hosts/host_list.html +0 -0
  64. {patchman-2.0.17 → patchman-3.0.0}/hosts/templates/hosts/host_table.html +0 -0
  65. {patchman-2.0.17 → patchman-3.0.0}/hosts/templatetags/__init__.py +0 -0
  66. {patchman-2.0.17 → patchman-3.0.0}/hosts/templatetags/report_alert.py +0 -0
  67. {patchman-2.0.17 → patchman-3.0.0}/hosts/urls.py +0 -0
  68. {patchman-2.0.17 → patchman-3.0.0}/hosts/utils.py +0 -0
  69. {patchman-2.0.17 → patchman-3.0.0}/hosts/views.py +0 -0
  70. {patchman-2.0.17/operatingsystems → patchman-3.0.0/modules}/__init__.py +0 -0
  71. {patchman-2.0.17/packages → patchman-3.0.0/operatingsystems}/__init__.py +0 -0
  72. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/admin.py +0 -0
  73. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/apps.py +0 -0
  74. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/forms.py +0 -0
  75. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/models.py +0 -0
  76. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/serializers.py +0 -0
  77. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/operatingsystem_table.html +0 -0
  78. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/operatingsystemgroup_table.html +0 -0
  79. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/os_delete.html +0 -0
  80. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/os_detail.html +0 -0
  81. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/os_list.html +0 -0
  82. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/osgroup_delete.html +0 -0
  83. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/osgroup_detail.html +0 -0
  84. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/templates/operatingsystems/osgroup_list.html +0 -0
  85. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/urls.py +0 -0
  86. {patchman-2.0.17 → patchman-3.0.0}/operatingsystems/views.py +0 -0
  87. {patchman-2.0.17/reports → patchman-3.0.0/packages}/__init__.py +0 -0
  88. {patchman-2.0.17 → patchman-3.0.0}/packages/admin.py +0 -0
  89. {patchman-2.0.17 → patchman-3.0.0}/packages/apps.py +0 -0
  90. {patchman-2.0.17 → patchman-3.0.0}/packages/managers.py +0 -0
  91. {patchman-2.0.17 → patchman-3.0.0}/packages/models.py +0 -0
  92. {patchman-2.0.17 → patchman-3.0.0}/packages/serializers.py +0 -0
  93. {patchman-2.0.17 → patchman-3.0.0}/packages/templates/packages/package_detail.html +0 -0
  94. {patchman-2.0.17 → patchman-3.0.0}/packages/templates/packages/package_list.html +0 -0
  95. {patchman-2.0.17 → patchman-3.0.0}/packages/templates/packages/package_table.html +0 -0
  96. {patchman-2.0.17 → patchman-3.0.0}/packages/urls.py +0 -0
  97. {patchman-2.0.17 → patchman-3.0.0}/packages/views.py +0 -0
  98. {patchman-2.0.17 → patchman-3.0.0}/patchman/__init__.py +0 -0
  99. {patchman-2.0.17 → patchman-3.0.0}/patchman/celery.py +0 -0
  100. {patchman-2.0.17 → patchman-3.0.0}/patchman/receivers.py +0 -0
  101. {patchman-2.0.17 → patchman-3.0.0}/patchman/signals.py +0 -0
  102. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/css/base.css +0 -0
  103. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/img/icon-alert.gif +0 -0
  104. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/img/icon-no.gif +0 -0
  105. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/img/icon-yes.gif +0 -0
  106. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/js/ajax-jquery.js +0 -0
  107. {patchman-2.0.17 → patchman-3.0.0}/patchman/static/js/button-post.js +0 -0
  108. {patchman-2.0.17 → patchman-3.0.0}/patchman/wsgi.py +0 -0
  109. {patchman-2.0.17 → patchman-3.0.0}/patchman.egg-info/dependency_links.txt +0 -0
  110. {patchman-2.0.17/repos → patchman-3.0.0/reports}/__init__.py +0 -0
  111. {patchman-2.0.17 → patchman-3.0.0}/reports/admin.py +0 -0
  112. {patchman-2.0.17 → patchman-3.0.0}/reports/apps.py +0 -0
  113. {patchman-2.0.17 → patchman-3.0.0}/reports/tasks.py +0 -0
  114. {patchman-2.0.17 → patchman-3.0.0}/reports/templates/reports/report_delete.html +0 -0
  115. {patchman-2.0.17 → patchman-3.0.0}/reports/templates/reports/report_list.html +0 -0
  116. {patchman-2.0.17 → patchman-3.0.0}/reports/templates/reports/report_table.html +0 -0
  117. {patchman-2.0.17 → patchman-3.0.0}/reports/urls.py +0 -0
  118. {patchman-2.0.17/repos/templatetags → patchman-3.0.0/repos}/__init__.py +0 -0
  119. {patchman-2.0.17 → patchman-3.0.0}/repos/admin.py +0 -0
  120. {patchman-2.0.17 → patchman-3.0.0}/repos/apps.py +0 -0
  121. {patchman-2.0.17 → patchman-3.0.0}/repos/forms.py +0 -0
  122. {patchman-2.0.17 → patchman-3.0.0}/repos/managers.py +0 -0
  123. {patchman-2.0.17 → patchman-3.0.0}/repos/models.py +0 -0
  124. {patchman-2.0.17 → patchman-3.0.0}/repos/serializers.py +0 -0
  125. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_delete.html +0 -0
  126. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_detail.html +0 -0
  127. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_edit.html +0 -0
  128. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_edit_repo.html +0 -0
  129. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_list.html +0 -0
  130. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_table.html +0 -0
  131. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/mirror_with_repo_list.html +0 -0
  132. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/repo_delete.html +0 -0
  133. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/repo_edit.html +0 -0
  134. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/repo_list.html +0 -0
  135. {patchman-2.0.17 → patchman-3.0.0}/repos/templates/repos/repository_table.html +0 -0
  136. {patchman-2.0.17/util → patchman-3.0.0/repos}/templatetags/__init__.py +0 -0
  137. {patchman-2.0.17 → patchman-3.0.0}/repos/templatetags/repo_buttons.py +0 -0
  138. {patchman-2.0.17 → patchman-3.0.0}/repos/urls.py +0 -0
  139. {patchman-2.0.17 → patchman-3.0.0}/repos/views.py +0 -0
  140. {patchman-2.0.17 → patchman-3.0.0}/sbin/patchman-manage +0 -0
  141. {patchman-2.0.17 → patchman-3.0.0}/sbin/patchman-set-secret-key +0 -0
  142. {patchman-2.0.17 → patchman-3.0.0}/scripts/clear-django-logs.py +0 -0
  143. {patchman-2.0.17 → patchman-3.0.0}/scripts/create_graph.sh +0 -0
  144. {patchman-2.0.17 → patchman-3.0.0}/scripts/rpm-install.sh +0 -0
  145. {patchman-2.0.17 → patchman-3.0.0}/setup.py +0 -0
  146. {patchman-2.0.17 → patchman-3.0.0}/util/__init__.py +0 -0
  147. {patchman-2.0.17 → patchman-3.0.0}/util/apps.py +0 -0
  148. {patchman-2.0.17 → patchman-3.0.0}/util/filterspecs.py +0 -0
  149. {patchman-2.0.17 → patchman-3.0.0}/util/templates/404.html +0 -0
  150. {patchman-2.0.17 → patchman-3.0.0}/util/templates/500.html +0 -0
  151. {patchman-2.0.17 → patchman-3.0.0}/util/templates/base.html +0 -0
  152. {patchman-2.0.17 → patchman-3.0.0}/util/templates/dashboard.html +0 -0
  153. {patchman-2.0.17 → patchman-3.0.0}/util/templates/navbar.html +0 -0
  154. {patchman-2.0.17 → patchman-3.0.0}/util/templates/objectlist.html +0 -0
  155. {patchman-2.0.17 → patchman-3.0.0}/util/templates/registration/login.html +0 -0
  156. {patchman-2.0.17 → patchman-3.0.0}/util/templates/searchbar.html +0 -0
  157. {patchman-2.0.17 → patchman-3.0.0}/util/templatetags/common.py +0 -0
  158. {patchman-2.0.17 → patchman-3.0.0}/util/urls.py +0 -0
  159. {patchman-2.0.17 → patchman-3.0.0}/util/views.py +0 -0
@@ -5,43 +5,48 @@ mysql or postgresql instead, see the database configuration section.
5
5
 
6
6
 
7
7
  ## Supported Install Options
8
- - [Ubuntu 20.04](#ubuntu-2004-focal)
9
- - [Debian 11](#debian-11-bullseye)
10
- - [CentOS 8](#centos-8)
8
+ - [Ubuntu 22.04](#ubuntu-2204-jammy)
9
+ - [Debian 12](#debian-12-bookworm)
10
+ - [CentOS 9](#centos-9)
11
11
  - [virtualenv + pip](#virtualenv--pip)
12
12
  - [Source](#source)
13
13
 
14
14
 
15
- ### Ubuntu 20.04 (focal)
15
+ ### Ubuntu 22.04 (jammy)
16
16
 
17
17
  ```shell
18
18
  curl -sS https://repo.openbytes.ie/openbytes.gpg > /usr/share/keyrings/openbytes.gpg
19
- echo "deb [signed-by=/usr/share/keyrings/openbytes.gpg] https://repo.openbytes.ie/patchman/ubuntu focal main" > /etc/apt/sources.list.d/patchman.list
19
+ echo "deb [signed-by=/usr/share/keyrings/openbytes.gpg] https://repo.openbytes.ie/patchman/ubuntu jammy main" > /etc/apt/sources.list.d/patchman.list
20
20
  apt update
21
21
  apt -y install python3-patchman patchman-client
22
22
  patchman-manage createsuperuser
23
23
  ```
24
24
 
25
- ### Debian 11 (bullseye)
25
+ ### Debian 12 (bookworm)
26
26
 
27
27
  ```shell
28
28
  curl -sS https://repo.openbytes.ie/openbytes.gpg > /usr/share/keyrings/openbytes.gpg
29
- echo "deb [signed-by=/usr/share/keyrings/openbytes.gpg] https://repo.openbytes.ie/patchman/debian bullseye main" > /etc/apt/sources.list.d/patchman.list
29
+ echo "deb [signed-by=/usr/share/keyrings/openbytes.gpg] https://repo.openbytes.ie/patchman/debian bookworm main" > /etc/apt/sources.list.d/patchman.list
30
30
  apt update
31
31
  apt -y install python3-patchman patchman-client
32
32
  patchman-manage createsuperuser
33
33
  ```
34
34
 
35
- ### CentOS 8
35
+ ### CentOS 9
36
+
37
+ This also applies to Rocky/Alma/RHEL
36
38
 
37
39
  ```shell
40
+ curl -sS https://repo.openbytes.ie/openbytes.gpg > /etc/pki/rpm-gpg/RPM-GPG-KEY-openbytes
38
41
  cat <<EOF >> /etc/yum.repos.d/openbytes.repo
39
42
  [openbytes]
40
43
  name=openbytes
41
- baseurl=https://repo.openbytes.ie/patchman/el8
44
+ baseurl=https://repo.openbytes.ie/patchman/el9
42
45
  enabled=1
43
- gpgcheck=0
46
+ gpgcheck=1
47
+ gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-openbytes
44
48
  EOF
49
+ update-crypto-policies --set DEFAULT:SHA1
45
50
  dnf -y install epel-release
46
51
  dnf makecache
47
52
  dnf -y install patchman patchman-client
@@ -55,7 +60,7 @@ TBD - not working yet
55
60
 
56
61
  ```shell
57
62
  apt -y install gcc libxml2-dev libxslt1-dev virtualenv python3-dev zlib1g-dev # (debian/ubuntu)
58
- dnf -y install gcc libxml2-devel libxslt-devel python3-virtualenv # (centos/rhel)
63
+ dnf -y install gcc libxml2-devel libxslt-devel python3-virtualenv # (centos/rocky/alma)
59
64
  mkdir /srv/patchman
60
65
  cd /srv/patchman
61
66
  virtualenv .
@@ -69,7 +74,7 @@ gunicorn patchman.wsgi -b 0.0.0.0:80
69
74
 
70
75
  ### Source
71
76
 
72
- #### Ubuntu 20.04 (focal)
77
+ #### Ubuntu 22.04 (jammy)
73
78
 
74
79
  1. Install dependencies
75
80
 
@@ -111,7 +116,7 @@ be configured:
111
116
 
112
117
  * ADMINS - set up an admin email address
113
118
  * SECRET_KEY - create a random secret key
114
- * STATICFILES_DIRS - should point to /srv/patchman/patchman/static if installing from
119
+ * STATIC_ROOT - should point to `/srv/patchman/run/static` if installing from
115
120
  source
116
121
 
117
122
 
@@ -212,6 +217,8 @@ postgres=# ALTER ROLE patchman SET timezone TO 'UTC';
212
217
  ALTER ROLE
213
218
  postgres=# GRANT ALL PRIVILEGES ON DATABASE patchman to patchman;
214
219
  GRANT
220
+ postgres=# GRANT ALL ON SCHEMA public TO patchman;
221
+ GRANT
215
222
  ```
216
223
 
217
224
  3. Modify `/etc/patchman/local_settings.py` as follows:
@@ -314,7 +321,9 @@ apt -y install python3-celery redis python3-redis python-celery-common
314
321
  C_FORCE_ROOT=1 celery -b redis://127.0.0.1:6379/0 -A patchman worker -l INFO -E
315
322
  ```
316
323
 
317
- #### CentOS / RHEL
324
+ #### CentOS / Rocky / Alma
325
+
326
+ Currently waiting on https://bugzilla.redhat.com/show_bug.cgi?id=2032543
318
327
 
319
328
  ```shell
320
329
  dnf -y install python3-celery redis python3-redis
@@ -334,8 +343,8 @@ Enable celery by adding `USE_ASYNC_PROCESSING = True` to `/etc/patchman/local_se
334
343
  Memcached can optionally be run to reduce the load on the server.
335
344
 
336
345
  ```shell
337
- apt -y install memcached python3-memcache # (debian/ubuntu)
338
- dnf -y install memcached python3-memcached # (centos/rhel)
346
+ apt -y install memcached python3-pymemcache # (debian/ubuntu)
347
+ dnf -y install memcached python3-pymemcache # (centos/rocky/alma)
339
348
  systemctl restart memcached
340
349
  ```
341
350
 
@@ -344,8 +353,11 @@ and add the following to `/etc/patchman/local_settings.py`
344
353
  ```
345
354
  CACHES = {
346
355
  'default': {
347
- 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
356
+ 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
348
357
  'LOCATION': '127.0.0.1:11211',
358
+ 'OPTIONS': {
359
+ 'ignore_exc': True,
360
+ },
349
361
  }
350
362
  }
351
363
  ```
@@ -15,5 +15,6 @@ recursive-include operatingsystems *
15
15
  recursive-include packages *
16
16
  recursive-include repos *
17
17
  recursive-include reports *
18
+ recursive-include modules *
18
19
  recursive-include sbin *
19
20
  recursive-include etc *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: patchman
3
- Version: 2.0.17
3
+ Version: 3.0.0
4
4
  Summary: Django based patch status monitoring tool for linux systems
5
5
  Home-page: http://patchman.openbytes.ie/
6
6
  Author: Marcus Furlong
@@ -15,23 +15,24 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: COPYING
17
17
  License-File: AUTHORS
18
- Requires-Dist: Django==2.2.28
18
+ Requires-Dist: Django==3.2.23
19
19
  Requires-Dist: django-tagging==0.5.0
20
- Requires-Dist: django-extensions==3.1.5
21
- Requires-Dist: django-bootstrap3==15.0.0
20
+ Requires-Dist: django-extensions==3.2.1
21
+ Requires-Dist: django-bootstrap3==23.1
22
22
  Requires-Dist: progressbar==2.5
23
- Requires-Dist: python-debian==0.1.43
24
- Requires-Dist: lxml==4.7.1
23
+ Requires-Dist: python-debian==0.1.49
24
+ Requires-Dist: lxml==4.9.2
25
25
  Requires-Dist: defusedxml==0.7.1
26
+ Requires-Dist: PyYAML==6.0
26
27
  Requires-Dist: chardet==4.0.0
27
- Requires-Dist: requests==2.27.1
28
+ Requires-Dist: requests==2.31.0
28
29
  Requires-Dist: colorama==0.4.4
29
30
  Requires-Dist: djangorestframework==3.13.1
30
31
  Requires-Dist: django-filter==21.1
31
32
  Requires-Dist: humanize==3.13.1
32
33
  Requires-Dist: version-utils==0.3.0
33
34
  Requires-Dist: python-magic==0.4.25
34
- Requires-Dist: python-memcached==1.59
35
+ Requires-Dist: pymemcache==4.0.0
35
36
 
36
37
  # Patchman
37
38
 
@@ -0,0 +1 @@
1
+ 3.0.0
@@ -40,7 +40,10 @@ RUN_GUNICORN = False
40
40
  # Enable memcached
41
41
  CACHES = {
42
42
  'default': {
43
- 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
43
+ 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
44
44
  'LOCATION': '127.0.0.1:11211',
45
+ 'OPTIONS': {
46
+ 'ignore_exc': True,
47
+ },
45
48
  }
46
49
  }
@@ -31,6 +31,7 @@ from domains.models import Domain
31
31
  from repos.models import Repository
32
32
  from operatingsystems.models import OS
33
33
  from arch.models import MachineArchitecture
34
+ from modules.models import Module
34
35
  from patchman.signals import info_message, error_message
35
36
  from packages.utils import get_or_create_package_update
36
37
  from repos.utils import find_best_repo
@@ -50,6 +51,7 @@ class Host(models.Model):
50
51
  lastreport = models.DateTimeField()
51
52
  packages = models.ManyToManyField(Package, blank=True)
52
53
  repos = models.ManyToManyField(Repository, blank=True, through='HostRepo')
54
+ modules = models.ManyToManyField(Module, blank=True)
53
55
  updates = models.ManyToManyField(PackageUpdate, blank=True)
54
56
  reboot_required = models.BooleanField(default=False)
55
57
  host_repos_only = models.BooleanField(default=True)
@@ -122,15 +124,18 @@ class Host(models.Model):
122
124
  def get_host_repo_packages(self):
123
125
  if self.host_repos_only:
124
126
  hostrepos_q = Q(mirror__repo__in=self.repos.all(),
125
- mirror__enabled=True, mirror__repo__enabled=True,
127
+ mirror__enabled=True,
128
+ mirror__repo__enabled=True,
126
129
  mirror__repo__hostrepo__enabled=True)
127
130
  else:
128
131
  hostrepos_q = \
129
132
  Q(mirror__repo__osgroup__os__host=self,
130
- mirror__repo__arch=self.arch, mirror__enabled=True,
133
+ mirror__repo__arch=self.arch,
134
+ mirror__enabled=True,
131
135
  mirror__repo__enabled=True) | \
132
136
  Q(mirror__repo__in=self.repos.all(),
133
- mirror__enabled=True, mirror__repo__enabled=True)
137
+ mirror__enabled=True,
138
+ mirror__repo__enabled=True)
134
139
  return Package.objects.select_related().filter(hostrepos_q).distinct()
135
140
 
136
141
  def process_update(self, package, highest_package):
@@ -221,10 +226,21 @@ class Host(models.Model):
221
226
  priority = best_repo.priority
222
227
 
223
228
  # find the packages that are potential updates
224
- pu_q = Q(name=package.name, arch=package.arch,
229
+ pu_q = Q(name=package.name,
230
+ arch=package.arch,
225
231
  packagetype=package.packagetype)
226
232
  potential_updates = repo_packages.filter(pu_q)
227
233
  for pu in potential_updates:
234
+ pu_is_module_package = False
235
+ pu_in_enabled_modules = False
236
+ if pu.module_set.exists():
237
+ pu_is_module_package = True
238
+ for module in pu.module_set.all():
239
+ if module in self.modules.all():
240
+ pu_in_enabled_modules = True
241
+ if pu_is_module_package:
242
+ if not pu_in_enabled_modules:
243
+ continue
228
244
  if highest_package.compare_version(pu) == -1 \
229
245
  and package.compare_version(pu) == -1:
230
246
 
@@ -257,6 +273,16 @@ class Host(models.Model):
257
273
  packagetype=package.packagetype)
258
274
  potential_updates = repo_packages.filter(pu_q)
259
275
  for pu in potential_updates:
276
+ pu_is_module_package = False
277
+ pu_in_enabled_modules = False
278
+ if pu.module_set.exists():
279
+ pu_is_module_package = True
280
+ for module in pu.module_set.all():
281
+ if module in self.modules.all():
282
+ pu_in_enabled_modules = True
283
+ if pu_is_module_package:
284
+ if not pu_in_enabled_modules:
285
+ continue
260
286
  if highest_package.compare_version(pu) == -1 \
261
287
  and package.compare_version(pu) == -1:
262
288
  highest_package = pu
@@ -14,6 +14,7 @@
14
14
  <li class="active"><a data-toggle="tab" href="#host_details">Details</a></li>
15
15
  <li><a data-toggle="tab" href="#host_updates">Updates Available</a></li>
16
16
  <li><a data-toggle="tab" href="#host_repos">Repos</a></li>
17
+ <li><a data-toggle="tab" href="#host_modules">Modules</a></li>
17
18
  <li><a data-toggle="tab" href="#host_packages">Packages</a></li>
18
19
  </ul>
19
20
 
@@ -135,6 +136,14 @@
135
136
  </div>
136
137
  </div>
137
138
 
139
+ <div class="tab-pane fade in" id="host_modules">
140
+ <div class="well well-sm">
141
+ <div class="well">
142
+ {% gen_table host.modules.all %}
143
+ </div>
144
+ </div>
145
+ </div>
146
+
138
147
  <div class="tab-pane fade in" id="host_packages">
139
148
  <div class="well well-sm">
140
149
  <button class="btn btn-primary btn-sm" data-toggle="collapse" data-target="#packages">Show/Hide Installed Packages</button>
@@ -0,0 +1,20 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.contrib import admin
18
+ from modules.models import Module
19
+
20
+ admin.site.register(Module)
@@ -0,0 +1,21 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.apps import AppConfig
18
+
19
+
20
+ class ModulesConfig(AppConfig):
21
+ name = 'modules'
@@ -0,0 +1,22 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.db import models
18
+
19
+
20
+ class ModuleManager(models.Manager):
21
+ def get_queryset(self):
22
+ return super().get_queryset().select_related()
@@ -0,0 +1,44 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.db import models
18
+ from django.urls import reverse
19
+
20
+ from arch.models import PackageArchitecture
21
+ from packages.models import Package
22
+ from repos.models import Repository
23
+
24
+
25
+ class Module(models.Model):
26
+
27
+ name = models.CharField(unique=True, max_length=255)
28
+ stream = models.CharField(unique=True, max_length=255)
29
+ version = models.CharField(max_length=255)
30
+ context = models.CharField(unique=True, max_length=255)
31
+ arch = models.ForeignKey(PackageArchitecture, on_delete=models.CASCADE)
32
+ repo = models.ForeignKey(Repository, on_delete=models.CASCADE)
33
+ packages = models.ManyToManyField(Package, blank=True)
34
+
35
+ class Meta:
36
+ verbose_name = 'Module'
37
+ verbose_name_plural = 'Modules'
38
+ ordering = ('name',)
39
+
40
+ def __str__(self):
41
+ return self.name
42
+
43
+ def get_absolute_url(self):
44
+ return reverse('modules:module_detail', args=[str(self.id)])
@@ -0,0 +1,25 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from rest_framework import serializers
18
+
19
+ from modules.models import Module
20
+
21
+
22
+ class ModuleSerializer(serializers.HyperlinkedModelSerializer):
23
+ class Meta:
24
+ model = Module
25
+ fields = ('id', 'name', 'stream', 'version', 'context', 'arch', 'repo', 'packages')
@@ -0,0 +1,69 @@
1
+ {% extends "base.html" %}
2
+
3
+ {% load common bootstrap3 %}
4
+
5
+ {% block page_title %}Module - {{ module }} {% endblock %}
6
+
7
+ {% block breadcrumbs %} {{ block.super }} <li><a href="{% url 'modules:module_list' %}">Modules</a></li><li class="active">{{ module }}</li>{% endblock %}
8
+
9
+ {% block content_title %}Module - {{ module }} {% endblock %}
10
+
11
+ {% block content %}
12
+
13
+ <ul class="nav nav-tabs">
14
+ <li class="active"><a data-toggle="tab" href="#module_details">Details</a></li>
15
+ <li><a data-toggle="tab" href="#module_packages">Packages</a></li>
16
+ <li><a data-toggle="tab" href="#module_hosts">Hosts with this Module Enabled</a></li>
17
+ </ul>
18
+
19
+ <div class="tab-content">
20
+ <div class="tab-pane fade in active" id="module_details">
21
+ <div class="well well-sm">
22
+ <table class="table table-striped table-bordered table-hover table-condensed table-responsive">
23
+ <tr><th>Name</th><td> {{ module.name }} </td></tr>
24
+ <tr><th>ID</th><td> {{ module.id }} </td></tr>
25
+ <tr><th>Stream</th><td> {{ module.stream }} </td></tr>
26
+ <tr><th>Version</th><td> {{ module.version }} </td></tr>
27
+ <tr><th>Context</th><td> {{ module.context }} </td></tr>
28
+ <tr><th>Architecture</th><td> {{ module.arch }} </td></tr>
29
+ <tr><th>Repo</th><td><a href="{{ module.repo.get_absolute_url }}">{{ module.repo }}</a></td></tr>
30
+ </table>
31
+ </div>
32
+ </div>
33
+
34
+ <div class="tab-pane fade in" id="module_packages">
35
+ <div class="well well-sm">
36
+ <table class="table table-striped table-bordered table-hover table-condensed table-responsive">
37
+ <thead>
38
+ <tr>
39
+ <th>Name</th>
40
+ <th>Epoch</th>
41
+ <th>Version</th>
42
+ <th>Release</th>
43
+ <th>Arch</th>
44
+ <th>Type</th>
45
+ </tr>
46
+ </thead>
47
+ <tbody>
48
+ {% for package in module.packages.all %}
49
+ <tr>
50
+ <td> {{ package.name }} </td>
51
+ <td> {{ package.epoch }} </td>
52
+ <td> {{ package.version }} </td>
53
+ <td> {{ package.release }} </td>
54
+ <td> {{ package.arch }} </td>
55
+ <td> {{ package.get_packagetype_display }} </td>
56
+ </tr>
57
+ {% endfor %}
58
+ </tbody>
59
+ </table>
60
+ </div>
61
+ </div>
62
+
63
+ <div class="tab-pane fade in" id="module_hosts">
64
+ <div class="well well-sm">
65
+ {% gen_table module.host_set.all.distinct %}
66
+ </div>
67
+ </div>
68
+ </div>
69
+ {% endblock %}
@@ -0,0 +1,7 @@
1
+ {% extends "objectlist.html" %}
2
+
3
+ {% block page_title %}Modules{% endblock %}
4
+
5
+ {% block breadcrumbs %} {{ block.super }} <li class="active"><a href="{% url 'modules:module_list' %}">Modules</a></li>{% endblock %}
6
+
7
+ {% block content_title %} Modules {% endblock %}
@@ -0,0 +1,23 @@
1
+ {% load common %}
2
+ <table class="table table-striped table-bordered table-hover table-condensed table-responsive">
3
+ <thead>
4
+ <tr>
5
+ <th class="col-sm-auto">Module</th>
6
+ <th class="col-sm-auto">ID</th>
7
+ <th class="col-sm-auto">Repo</th>
8
+ <th class="col-sm-auto">Packages</th>
9
+ <th class="col-md-auto">Enabled on Hosts</th>
10
+ </tr>
11
+ </thead>
12
+ <tbody>
13
+ {% for module in object_list %}
14
+ <tr>
15
+ <td><a href="{{ module.get_absolute_url }}">{{ module }}</a></td>
16
+ <td>{{ module.id }}</td>
17
+ <td><a href="{{ module.repo.get_absolute_url }}">{{ module.repo }}</a></td>
18
+ <td>{{ module.packages.count }}</td>
19
+ <td>{{ module.host_set.count }}</td>
20
+ </tr>
21
+ {% endfor %}
22
+ </tbody>
23
+ </table>
@@ -0,0 +1,26 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.urls import path
18
+
19
+ from modules import views
20
+
21
+ app_name = 'modules'
22
+
23
+ urlpatterns = [
24
+ path('', views.module_list, name='module_list'),
25
+ path('<int:module_id>/', views.module_detail, name='module_detail'),
26
+ ]
@@ -0,0 +1,74 @@
1
+ # Copyright 2023 Marcus Furlong <furlongm@gmail.com>
2
+ #
3
+ # This file is part of Patchman.
4
+ #
5
+ # Patchman is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 only.
8
+ #
9
+ # Patchman is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with Patchman. If not, see <http://www.gnu.org/licenses/>
16
+
17
+ from django.shortcuts import get_object_or_404, render
18
+ from django.contrib.auth.decorators import login_required
19
+ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
20
+ from django.db.models import Q
21
+
22
+ from rest_framework import viewsets, permissions
23
+
24
+ from modules.models import Module
25
+ from modules.serializers import ModuleSerializer
26
+
27
+
28
+ @login_required
29
+ def module_list(request):
30
+
31
+ modules = Module.objects.select_related()
32
+
33
+ if 'search' in request.GET:
34
+ terms = request.GET['search'].lower()
35
+ query = Q()
36
+ for term in terms.split(' '):
37
+ q = Q(name__icontains=term)
38
+ query = query & q
39
+ modules = modules.filter(query)
40
+ else:
41
+ terms = ''
42
+
43
+ page_no = request.GET.get('page')
44
+ paginator = Paginator(modules, 50)
45
+
46
+ try:
47
+ page = paginator.page(page_no)
48
+ except PageNotAnInteger:
49
+ page = paginator.page(1)
50
+ except EmptyPage:
51
+ page = paginator.page(paginator.num_pages)
52
+
53
+ return render(request,
54
+ 'modules/module_list.html',
55
+ {'page': page,
56
+ 'terms': terms}, )
57
+
58
+
59
+ @login_required
60
+ def module_detail(request, module_id):
61
+
62
+ module = get_object_or_404(Module, id=module_id)
63
+ return render(request,
64
+ 'modules/module_detail.html',
65
+ {'module': module}, )
66
+
67
+
68
+ class ModuleViewSet(viewsets.ModelViewSet):
69
+ """
70
+ API endpoint that allows modules to be viewed or edited.
71
+ """
72
+ queryset = Module.objects.all()
73
+ serializer_class = ModuleSerializer
74
+ permission_classes = (permissions.IsAuthenticatedOrReadOnly,)