django-cfg 1.2.15__py3-none-any.whl → 1.2.16__py3-none-any.whl
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.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/maintenance/README.md +305 -0
- django_cfg/apps/maintenance/__init__.py +27 -0
- django_cfg/apps/maintenance/admin/__init__.py +28 -0
- django_cfg/apps/maintenance/admin/deployments_admin.py +251 -0
- django_cfg/apps/maintenance/admin/events_admin.py +374 -0
- django_cfg/apps/maintenance/admin/monitoring_admin.py +215 -0
- django_cfg/apps/maintenance/admin/sites_admin.py +464 -0
- django_cfg/apps/maintenance/apps.py +105 -0
- django_cfg/apps/maintenance/management/__init__.py +0 -0
- django_cfg/apps/maintenance/management/commands/__init__.py +0 -0
- django_cfg/apps/maintenance/management/commands/maintenance.py +375 -0
- django_cfg/apps/maintenance/management/commands/sync_cloudflare.py +168 -0
- django_cfg/apps/maintenance/managers/__init__.py +20 -0
- django_cfg/apps/maintenance/managers/deployments.py +287 -0
- django_cfg/apps/maintenance/managers/events.py +374 -0
- django_cfg/apps/maintenance/managers/monitoring.py +301 -0
- django_cfg/apps/maintenance/managers/sites.py +335 -0
- django_cfg/apps/maintenance/migrations/0001_initial.py +939 -0
- django_cfg/apps/maintenance/migrations/__init__.py +0 -0
- django_cfg/apps/maintenance/models/__init__.py +27 -0
- django_cfg/apps/maintenance/models/cloudflare.py +316 -0
- django_cfg/apps/maintenance/models/maintenance.py +334 -0
- django_cfg/apps/maintenance/models/monitoring.py +393 -0
- django_cfg/apps/maintenance/models/sites.py +419 -0
- django_cfg/apps/maintenance/serializers/__init__.py +60 -0
- django_cfg/apps/maintenance/serializers/actions.py +310 -0
- django_cfg/apps/maintenance/serializers/base.py +44 -0
- django_cfg/apps/maintenance/serializers/deployments.py +209 -0
- django_cfg/apps/maintenance/serializers/events.py +210 -0
- django_cfg/apps/maintenance/serializers/monitoring.py +278 -0
- django_cfg/apps/maintenance/serializers/sites.py +213 -0
- django_cfg/apps/maintenance/services/README.md +168 -0
- django_cfg/apps/maintenance/services/__init__.py +21 -0
- django_cfg/apps/maintenance/services/cloudflare_client.py +441 -0
- django_cfg/apps/maintenance/services/dns_manager.py +497 -0
- django_cfg/apps/maintenance/services/maintenance_manager.py +504 -0
- django_cfg/apps/maintenance/services/site_sync.py +448 -0
- django_cfg/apps/maintenance/services/sync_command_service.py +330 -0
- django_cfg/apps/maintenance/services/worker_manager.py +264 -0
- django_cfg/apps/maintenance/signals.py +38 -0
- django_cfg/apps/maintenance/urls.py +36 -0
- django_cfg/apps/maintenance/views/__init__.py +18 -0
- django_cfg/apps/maintenance/views/base.py +61 -0
- django_cfg/apps/maintenance/views/deployments.py +175 -0
- django_cfg/apps/maintenance/views/events.py +204 -0
- django_cfg/apps/maintenance/views/monitoring.py +213 -0
- django_cfg/apps/maintenance/views/sites.py +338 -0
- django_cfg/apps/urls.py +5 -1
- django_cfg/core/config.py +34 -3
- django_cfg/core/generation.py +15 -10
- django_cfg/models/cloudflare.py +316 -0
- django_cfg/models/revolution.py +1 -1
- django_cfg/models/tasks.py +1 -1
- django_cfg/modules/base.py +12 -5
- django_cfg/modules/django_unfold/dashboard.py +16 -1
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/METADATA +2 -1
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/RECORD +61 -13
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,939 @@
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-09-22 17:18
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
import django.utils.timezone
|
5
|
+
from django.conf import settings
|
6
|
+
from django.db import migrations, models
|
7
|
+
|
8
|
+
|
9
|
+
class Migration(migrations.Migration):
|
10
|
+
|
11
|
+
initial = True
|
12
|
+
|
13
|
+
dependencies = [
|
14
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
15
|
+
]
|
16
|
+
|
17
|
+
operations = [
|
18
|
+
migrations.CreateModel(
|
19
|
+
name="CloudflareSite",
|
20
|
+
fields=[
|
21
|
+
(
|
22
|
+
"id",
|
23
|
+
models.BigAutoField(
|
24
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
25
|
+
),
|
26
|
+
),
|
27
|
+
(
|
28
|
+
"name",
|
29
|
+
models.CharField(
|
30
|
+
help_text="Friendly site name for identification", max_length=100
|
31
|
+
),
|
32
|
+
),
|
33
|
+
(
|
34
|
+
"domain",
|
35
|
+
models.CharField(
|
36
|
+
help_text="Domain name (e.g., example.com)", max_length=253, unique=True
|
37
|
+
),
|
38
|
+
),
|
39
|
+
(
|
40
|
+
"description",
|
41
|
+
models.TextField(blank=True, help_text="Site description or notes"),
|
42
|
+
),
|
43
|
+
(
|
44
|
+
"zone_id",
|
45
|
+
models.CharField(help_text="Cloudflare Zone ID", max_length=32, unique=True),
|
46
|
+
),
|
47
|
+
("account_id", models.CharField(help_text="Cloudflare Account ID", max_length=32)),
|
48
|
+
(
|
49
|
+
"api_token",
|
50
|
+
models.CharField(
|
51
|
+
help_text="Site-specific or account API token", max_length=200
|
52
|
+
),
|
53
|
+
),
|
54
|
+
(
|
55
|
+
"environment",
|
56
|
+
models.CharField(
|
57
|
+
choices=[
|
58
|
+
("production", "Production"),
|
59
|
+
("staging", "Staging"),
|
60
|
+
("development", "Development"),
|
61
|
+
("testing", "Testing"),
|
62
|
+
],
|
63
|
+
default="production",
|
64
|
+
help_text="Site environment type",
|
65
|
+
max_length=20,
|
66
|
+
),
|
67
|
+
),
|
68
|
+
(
|
69
|
+
"project",
|
70
|
+
models.CharField(
|
71
|
+
blank=True, help_text="Project or client name", max_length=100
|
72
|
+
),
|
73
|
+
),
|
74
|
+
(
|
75
|
+
"tags",
|
76
|
+
models.JSONField(
|
77
|
+
blank=True,
|
78
|
+
default=list,
|
79
|
+
help_text="Custom tags for filtering and organization",
|
80
|
+
),
|
81
|
+
),
|
82
|
+
(
|
83
|
+
"current_status",
|
84
|
+
models.CharField(
|
85
|
+
choices=[
|
86
|
+
("active", "Active"),
|
87
|
+
("maintenance", "Under Maintenance"),
|
88
|
+
("offline", "Offline"),
|
89
|
+
("unknown", "Unknown"),
|
90
|
+
],
|
91
|
+
default="unknown",
|
92
|
+
help_text="Current operational status",
|
93
|
+
max_length=20,
|
94
|
+
),
|
95
|
+
),
|
96
|
+
(
|
97
|
+
"maintenance_active",
|
98
|
+
models.BooleanField(
|
99
|
+
default=False, help_text="Whether maintenance mode is currently active"
|
100
|
+
),
|
101
|
+
),
|
102
|
+
(
|
103
|
+
"last_status_check",
|
104
|
+
models.DateTimeField(
|
105
|
+
blank=True, help_text="When status was last checked", null=True
|
106
|
+
),
|
107
|
+
),
|
108
|
+
(
|
109
|
+
"worker_name",
|
110
|
+
models.CharField(
|
111
|
+
default="maintenance-mode",
|
112
|
+
help_text="Cloudflare Worker name for maintenance mode",
|
113
|
+
max_length=100,
|
114
|
+
),
|
115
|
+
),
|
116
|
+
(
|
117
|
+
"maintenance_template",
|
118
|
+
models.CharField(
|
119
|
+
default="modern", help_text="Maintenance page template", max_length=50
|
120
|
+
),
|
121
|
+
),
|
122
|
+
(
|
123
|
+
"custom_maintenance_message",
|
124
|
+
models.TextField(
|
125
|
+
blank=True, help_text="Custom maintenance message for this site"
|
126
|
+
),
|
127
|
+
),
|
128
|
+
(
|
129
|
+
"monitoring_enabled",
|
130
|
+
models.BooleanField(
|
131
|
+
default=True, help_text="Enable health monitoring for this site"
|
132
|
+
),
|
133
|
+
),
|
134
|
+
(
|
135
|
+
"health_check_url",
|
136
|
+
models.URLField(
|
137
|
+
blank=True, help_text="Custom health check URL (defaults to domain/health/)"
|
138
|
+
),
|
139
|
+
),
|
140
|
+
(
|
141
|
+
"check_interval",
|
142
|
+
models.PositiveIntegerField(
|
143
|
+
default=300, help_text="Health check interval in seconds"
|
144
|
+
),
|
145
|
+
),
|
146
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
147
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
148
|
+
(
|
149
|
+
"last_maintenance_at",
|
150
|
+
models.DateTimeField(
|
151
|
+
blank=True, help_text="When maintenance was last activated", null=True
|
152
|
+
),
|
153
|
+
),
|
154
|
+
(
|
155
|
+
"allowed_users",
|
156
|
+
models.ManyToManyField(
|
157
|
+
blank=True,
|
158
|
+
help_text="Users with access to manage this site",
|
159
|
+
related_name="accessible_sites",
|
160
|
+
to=settings.AUTH_USER_MODEL,
|
161
|
+
),
|
162
|
+
),
|
163
|
+
(
|
164
|
+
"owner",
|
165
|
+
models.ForeignKey(
|
166
|
+
help_text="Site owner",
|
167
|
+
on_delete=django.db.models.deletion.CASCADE,
|
168
|
+
related_name="owned_sites",
|
169
|
+
to=settings.AUTH_USER_MODEL,
|
170
|
+
),
|
171
|
+
),
|
172
|
+
],
|
173
|
+
options={
|
174
|
+
"verbose_name": "Cloudflare Site",
|
175
|
+
"verbose_name_plural": "Cloudflare Sites",
|
176
|
+
"ordering": ["name"],
|
177
|
+
},
|
178
|
+
),
|
179
|
+
migrations.CreateModel(
|
180
|
+
name="MaintenanceEvent",
|
181
|
+
fields=[
|
182
|
+
(
|
183
|
+
"id",
|
184
|
+
models.BigAutoField(
|
185
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
186
|
+
),
|
187
|
+
),
|
188
|
+
(
|
189
|
+
"title",
|
190
|
+
models.CharField(
|
191
|
+
help_text="Human-readable maintenance event title", max_length=200
|
192
|
+
),
|
193
|
+
),
|
194
|
+
(
|
195
|
+
"description",
|
196
|
+
models.TextField(
|
197
|
+
blank=True, help_text="Detailed description of maintenance work"
|
198
|
+
),
|
199
|
+
),
|
200
|
+
(
|
201
|
+
"reason",
|
202
|
+
models.CharField(
|
203
|
+
choices=[
|
204
|
+
("manual", "Manual Activation"),
|
205
|
+
("server_down", "Server Unreachable"),
|
206
|
+
("high_error_rate", "High Error Rate"),
|
207
|
+
("database_issues", "Database Issues"),
|
208
|
+
("deployment", "Deployment"),
|
209
|
+
("security_update", "Security Update"),
|
210
|
+
("scheduled", "Scheduled Maintenance"),
|
211
|
+
("emergency", "Emergency Maintenance"),
|
212
|
+
],
|
213
|
+
default="manual",
|
214
|
+
help_text="Reason for maintenance activation",
|
215
|
+
max_length=50,
|
216
|
+
),
|
217
|
+
),
|
218
|
+
(
|
219
|
+
"status",
|
220
|
+
models.CharField(
|
221
|
+
choices=[
|
222
|
+
("scheduled", "Scheduled"),
|
223
|
+
("active", "Active"),
|
224
|
+
("completed", "Completed"),
|
225
|
+
("failed", "Failed"),
|
226
|
+
("cancelled", "Cancelled"),
|
227
|
+
],
|
228
|
+
default="active",
|
229
|
+
help_text="Current maintenance status",
|
230
|
+
max_length=20,
|
231
|
+
),
|
232
|
+
),
|
233
|
+
(
|
234
|
+
"started_at",
|
235
|
+
models.DateTimeField(
|
236
|
+
default=django.utils.timezone.now, help_text="When maintenance was started"
|
237
|
+
),
|
238
|
+
),
|
239
|
+
(
|
240
|
+
"ended_at",
|
241
|
+
models.DateTimeField(
|
242
|
+
blank=True, help_text="When maintenance was completed", null=True
|
243
|
+
),
|
244
|
+
),
|
245
|
+
(
|
246
|
+
"estimated_duration",
|
247
|
+
models.DurationField(
|
248
|
+
blank=True, help_text="Estimated maintenance duration", null=True
|
249
|
+
),
|
250
|
+
),
|
251
|
+
(
|
252
|
+
"cloudflare_worker_deployed",
|
253
|
+
models.BooleanField(
|
254
|
+
default=False, help_text="Whether Cloudflare Worker was deployed"
|
255
|
+
),
|
256
|
+
),
|
257
|
+
(
|
258
|
+
"cloudflare_deployment_id",
|
259
|
+
models.CharField(
|
260
|
+
blank=True, help_text="Cloudflare deployment identifier", max_length=100
|
261
|
+
),
|
262
|
+
),
|
263
|
+
(
|
264
|
+
"worker_deployment_success",
|
265
|
+
models.BooleanField(
|
266
|
+
default=False, help_text="Whether Worker deployment was successful"
|
267
|
+
),
|
268
|
+
),
|
269
|
+
(
|
270
|
+
"affected_requests",
|
271
|
+
models.PositiveIntegerField(
|
272
|
+
default=0, help_text="Number of requests affected during maintenance"
|
273
|
+
),
|
274
|
+
),
|
275
|
+
(
|
276
|
+
"error_count_before",
|
277
|
+
models.PositiveIntegerField(
|
278
|
+
default=0, help_text="Error count before maintenance"
|
279
|
+
),
|
280
|
+
),
|
281
|
+
(
|
282
|
+
"error_count_during",
|
283
|
+
models.PositiveIntegerField(
|
284
|
+
default=0, help_text="Error count during maintenance"
|
285
|
+
),
|
286
|
+
),
|
287
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
288
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
289
|
+
(
|
290
|
+
"completed_by",
|
291
|
+
models.ForeignKey(
|
292
|
+
blank=True,
|
293
|
+
help_text="User who completed maintenance",
|
294
|
+
null=True,
|
295
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
296
|
+
related_name="completed_maintenance_events",
|
297
|
+
to=settings.AUTH_USER_MODEL,
|
298
|
+
),
|
299
|
+
),
|
300
|
+
(
|
301
|
+
"initiated_by",
|
302
|
+
models.ForeignKey(
|
303
|
+
blank=True,
|
304
|
+
help_text="User who initiated maintenance",
|
305
|
+
null=True,
|
306
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
307
|
+
related_name="initiated_maintenance_events",
|
308
|
+
to=settings.AUTH_USER_MODEL,
|
309
|
+
),
|
310
|
+
),
|
311
|
+
(
|
312
|
+
"sites",
|
313
|
+
models.ManyToManyField(
|
314
|
+
blank=True,
|
315
|
+
help_text="Sites affected by this maintenance event",
|
316
|
+
related_name="maintenance_events",
|
317
|
+
to="django_cfg_maintenance.cloudflaresite",
|
318
|
+
),
|
319
|
+
),
|
320
|
+
],
|
321
|
+
options={
|
322
|
+
"verbose_name": "Maintenance Event",
|
323
|
+
"verbose_name_plural": "Maintenance Events",
|
324
|
+
"ordering": ["-started_at"],
|
325
|
+
},
|
326
|
+
),
|
327
|
+
migrations.CreateModel(
|
328
|
+
name="CloudflareDeployment",
|
329
|
+
fields=[
|
330
|
+
(
|
331
|
+
"id",
|
332
|
+
models.BigAutoField(
|
333
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
334
|
+
),
|
335
|
+
),
|
336
|
+
(
|
337
|
+
"deployment_type",
|
338
|
+
models.CharField(
|
339
|
+
choices=[
|
340
|
+
("worker", "Cloudflare Worker"),
|
341
|
+
("page_rule", "Page Rule"),
|
342
|
+
("dns_record", "DNS Record"),
|
343
|
+
("ssl_setting", "SSL Setting"),
|
344
|
+
("custom_error_page", "Custom Error Page"),
|
345
|
+
],
|
346
|
+
default="worker",
|
347
|
+
help_text="Type of Cloudflare resource being deployed",
|
348
|
+
max_length=50,
|
349
|
+
),
|
350
|
+
),
|
351
|
+
(
|
352
|
+
"resource_name",
|
353
|
+
models.CharField(
|
354
|
+
help_text="Name of the deployed resource (Worker name, Page Rule, etc.)",
|
355
|
+
max_length=200,
|
356
|
+
),
|
357
|
+
),
|
358
|
+
(
|
359
|
+
"resource_id",
|
360
|
+
models.CharField(
|
361
|
+
blank=True,
|
362
|
+
help_text="Cloudflare resource ID after deployment",
|
363
|
+
max_length=100,
|
364
|
+
),
|
365
|
+
),
|
366
|
+
(
|
367
|
+
"status",
|
368
|
+
models.CharField(
|
369
|
+
choices=[
|
370
|
+
("pending", "Pending"),
|
371
|
+
("deploying", "Deploying"),
|
372
|
+
("deployed", "Deployed"),
|
373
|
+
("failed", "Failed"),
|
374
|
+
("rolled_back", "Rolled Back"),
|
375
|
+
],
|
376
|
+
default="pending",
|
377
|
+
help_text="Current deployment status",
|
378
|
+
max_length=20,
|
379
|
+
),
|
380
|
+
),
|
381
|
+
(
|
382
|
+
"created_at",
|
383
|
+
models.DateTimeField(
|
384
|
+
auto_now_add=True, help_text="When deployment was initiated"
|
385
|
+
),
|
386
|
+
),
|
387
|
+
(
|
388
|
+
"deployed_at",
|
389
|
+
models.DateTimeField(
|
390
|
+
blank=True, help_text="When deployment completed successfully", null=True
|
391
|
+
),
|
392
|
+
),
|
393
|
+
(
|
394
|
+
"failed_at",
|
395
|
+
models.DateTimeField(blank=True, help_text="When deployment failed", null=True),
|
396
|
+
),
|
397
|
+
(
|
398
|
+
"configuration",
|
399
|
+
models.JSONField(
|
400
|
+
default=dict,
|
401
|
+
help_text="Deployment configuration (Worker script, Page Rule settings, etc.)",
|
402
|
+
),
|
403
|
+
),
|
404
|
+
(
|
405
|
+
"cloudflare_response",
|
406
|
+
models.JSONField(
|
407
|
+
blank=True, default=dict, help_text="Full response from Cloudflare API"
|
408
|
+
),
|
409
|
+
),
|
410
|
+
(
|
411
|
+
"error_message",
|
412
|
+
models.TextField(blank=True, help_text="Error message if deployment failed"),
|
413
|
+
),
|
414
|
+
(
|
415
|
+
"rollback_data",
|
416
|
+
models.JSONField(
|
417
|
+
blank=True,
|
418
|
+
default=dict,
|
419
|
+
help_text="Data needed for rollback (previous configuration, etc.)",
|
420
|
+
),
|
421
|
+
),
|
422
|
+
(
|
423
|
+
"previous_deployment",
|
424
|
+
models.ForeignKey(
|
425
|
+
blank=True,
|
426
|
+
help_text="Previous deployment for rollback",
|
427
|
+
null=True,
|
428
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
429
|
+
related_name="rollback_deployments",
|
430
|
+
to="django_cfg_maintenance.cloudflaredeployment",
|
431
|
+
),
|
432
|
+
),
|
433
|
+
(
|
434
|
+
"site",
|
435
|
+
models.ForeignKey(
|
436
|
+
help_text="Site this deployment belongs to",
|
437
|
+
on_delete=django.db.models.deletion.CASCADE,
|
438
|
+
related_name="deployments",
|
439
|
+
to="django_cfg_maintenance.cloudflaresite",
|
440
|
+
),
|
441
|
+
),
|
442
|
+
(
|
443
|
+
"maintenance_event",
|
444
|
+
models.ForeignKey(
|
445
|
+
blank=True,
|
446
|
+
help_text="Related maintenance event",
|
447
|
+
null=True,
|
448
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
449
|
+
related_name="cloudflare_deployments",
|
450
|
+
to="django_cfg_maintenance.maintenanceevent",
|
451
|
+
),
|
452
|
+
),
|
453
|
+
],
|
454
|
+
options={
|
455
|
+
"verbose_name": "Cloudflare Deployment",
|
456
|
+
"verbose_name_plural": "Cloudflare Deployments",
|
457
|
+
"ordering": ["-created_at"],
|
458
|
+
},
|
459
|
+
),
|
460
|
+
migrations.CreateModel(
|
461
|
+
name="MaintenanceLog",
|
462
|
+
fields=[
|
463
|
+
(
|
464
|
+
"id",
|
465
|
+
models.BigAutoField(
|
466
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
467
|
+
),
|
468
|
+
),
|
469
|
+
(
|
470
|
+
"level",
|
471
|
+
models.CharField(
|
472
|
+
choices=[
|
473
|
+
("debug", "Debug"),
|
474
|
+
("info", "Info"),
|
475
|
+
("warning", "Warning"),
|
476
|
+
("error", "Error"),
|
477
|
+
("critical", "Critical"),
|
478
|
+
],
|
479
|
+
default="info",
|
480
|
+
help_text="Log level",
|
481
|
+
max_length=20,
|
482
|
+
),
|
483
|
+
),
|
484
|
+
("message", models.TextField(help_text="Log message")),
|
485
|
+
(
|
486
|
+
"details",
|
487
|
+
models.JSONField(
|
488
|
+
blank=True, default=dict, help_text="Additional log details (JSON)"
|
489
|
+
),
|
490
|
+
),
|
491
|
+
(
|
492
|
+
"component",
|
493
|
+
models.CharField(
|
494
|
+
blank=True,
|
495
|
+
help_text="Component that generated the log (e.g., 'cloudflare', 'monitoring')",
|
496
|
+
max_length=100,
|
497
|
+
),
|
498
|
+
),
|
499
|
+
(
|
500
|
+
"operation",
|
501
|
+
models.CharField(
|
502
|
+
blank=True,
|
503
|
+
help_text="Operation being performed (e.g., 'deploy_worker', 'health_check')",
|
504
|
+
max_length=100,
|
505
|
+
),
|
506
|
+
),
|
507
|
+
(
|
508
|
+
"timestamp",
|
509
|
+
models.DateTimeField(
|
510
|
+
default=django.utils.timezone.now,
|
511
|
+
help_text="When the log entry was created",
|
512
|
+
),
|
513
|
+
),
|
514
|
+
(
|
515
|
+
"event",
|
516
|
+
models.ForeignKey(
|
517
|
+
help_text="Related maintenance event",
|
518
|
+
on_delete=django.db.models.deletion.CASCADE,
|
519
|
+
related_name="logs",
|
520
|
+
to="django_cfg_maintenance.maintenanceevent",
|
521
|
+
),
|
522
|
+
),
|
523
|
+
(
|
524
|
+
"user",
|
525
|
+
models.ForeignKey(
|
526
|
+
blank=True,
|
527
|
+
help_text="User associated with this log entry",
|
528
|
+
null=True,
|
529
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
530
|
+
to=settings.AUTH_USER_MODEL,
|
531
|
+
),
|
532
|
+
),
|
533
|
+
],
|
534
|
+
options={
|
535
|
+
"verbose_name": "Maintenance Log",
|
536
|
+
"verbose_name_plural": "Maintenance Logs",
|
537
|
+
"ordering": ["-timestamp"],
|
538
|
+
},
|
539
|
+
),
|
540
|
+
migrations.CreateModel(
|
541
|
+
name="MonitoringTarget",
|
542
|
+
fields=[
|
543
|
+
(
|
544
|
+
"id",
|
545
|
+
models.BigAutoField(
|
546
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
547
|
+
),
|
548
|
+
),
|
549
|
+
("check_url", models.URLField(help_text="URL to check for health status")),
|
550
|
+
(
|
551
|
+
"check_interval",
|
552
|
+
models.PositiveIntegerField(default=60, help_text="Check interval in seconds"),
|
553
|
+
),
|
554
|
+
(
|
555
|
+
"timeout",
|
556
|
+
models.PositiveIntegerField(default=10, help_text="Request timeout in seconds"),
|
557
|
+
),
|
558
|
+
(
|
559
|
+
"expected_status_codes",
|
560
|
+
models.JSONField(
|
561
|
+
default=list, help_text="Expected HTTP status codes (e.g., [200, 201])"
|
562
|
+
),
|
563
|
+
),
|
564
|
+
(
|
565
|
+
"expected_response_time_ms",
|
566
|
+
models.PositiveIntegerField(
|
567
|
+
blank=True,
|
568
|
+
help_text="Maximum expected response time in milliseconds",
|
569
|
+
null=True,
|
570
|
+
),
|
571
|
+
),
|
572
|
+
(
|
573
|
+
"expected_content",
|
574
|
+
models.TextField(
|
575
|
+
blank=True, help_text="Expected content in response body (substring match)"
|
576
|
+
),
|
577
|
+
),
|
578
|
+
(
|
579
|
+
"failure_threshold",
|
580
|
+
models.PositiveIntegerField(
|
581
|
+
default=3, help_text="Consecutive failures before triggering maintenance"
|
582
|
+
),
|
583
|
+
),
|
584
|
+
(
|
585
|
+
"recovery_threshold",
|
586
|
+
models.PositiveIntegerField(
|
587
|
+
default=2, help_text="Consecutive successes before disabling maintenance"
|
588
|
+
),
|
589
|
+
),
|
590
|
+
(
|
591
|
+
"status",
|
592
|
+
models.CharField(
|
593
|
+
choices=[
|
594
|
+
("active", "Active"),
|
595
|
+
("paused", "Paused"),
|
596
|
+
("disabled", "Disabled"),
|
597
|
+
("error", "Error"),
|
598
|
+
],
|
599
|
+
default="active",
|
600
|
+
help_text="Current monitoring status",
|
601
|
+
max_length=20,
|
602
|
+
),
|
603
|
+
),
|
604
|
+
(
|
605
|
+
"consecutive_failures",
|
606
|
+
models.PositiveIntegerField(
|
607
|
+
default=0, help_text="Current consecutive failure count"
|
608
|
+
),
|
609
|
+
),
|
610
|
+
(
|
611
|
+
"consecutive_successes",
|
612
|
+
models.PositiveIntegerField(
|
613
|
+
default=0, help_text="Current consecutive success count"
|
614
|
+
),
|
615
|
+
),
|
616
|
+
(
|
617
|
+
"last_check_at",
|
618
|
+
models.DateTimeField(
|
619
|
+
blank=True, help_text="When last health check was performed", null=True
|
620
|
+
),
|
621
|
+
),
|
622
|
+
(
|
623
|
+
"last_check_success",
|
624
|
+
models.BooleanField(
|
625
|
+
default=True, help_text="Whether last check was successful"
|
626
|
+
),
|
627
|
+
),
|
628
|
+
(
|
629
|
+
"last_response_time_ms",
|
630
|
+
models.PositiveIntegerField(
|
631
|
+
blank=True,
|
632
|
+
help_text="Response time of last check in milliseconds",
|
633
|
+
null=True,
|
634
|
+
),
|
635
|
+
),
|
636
|
+
(
|
637
|
+
"auto_enable_maintenance",
|
638
|
+
models.BooleanField(
|
639
|
+
default=True,
|
640
|
+
help_text="Automatically enable maintenance on failure threshold",
|
641
|
+
),
|
642
|
+
),
|
643
|
+
(
|
644
|
+
"auto_disable_maintenance",
|
645
|
+
models.BooleanField(
|
646
|
+
default=True,
|
647
|
+
help_text="Automatically disable maintenance on recovery threshold",
|
648
|
+
),
|
649
|
+
),
|
650
|
+
(
|
651
|
+
"maintenance_triggered_at",
|
652
|
+
models.DateTimeField(
|
653
|
+
blank=True, help_text="When maintenance was last auto-triggered", null=True
|
654
|
+
),
|
655
|
+
),
|
656
|
+
(
|
657
|
+
"user_agent",
|
658
|
+
models.CharField(
|
659
|
+
default="Django-CFG-Monitor/1.0",
|
660
|
+
help_text="User agent for health checks",
|
661
|
+
max_length=200,
|
662
|
+
),
|
663
|
+
),
|
664
|
+
(
|
665
|
+
"follow_redirects",
|
666
|
+
models.BooleanField(
|
667
|
+
default=True, help_text="Follow HTTP redirects during checks"
|
668
|
+
),
|
669
|
+
),
|
670
|
+
(
|
671
|
+
"verify_ssl",
|
672
|
+
models.BooleanField(default=True, help_text="Verify SSL certificates"),
|
673
|
+
),
|
674
|
+
(
|
675
|
+
"custom_headers",
|
676
|
+
models.JSONField(
|
677
|
+
blank=True,
|
678
|
+
default=dict,
|
679
|
+
help_text="Custom headers for health check requests",
|
680
|
+
),
|
681
|
+
),
|
682
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
683
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
684
|
+
(
|
685
|
+
"site",
|
686
|
+
models.OneToOneField(
|
687
|
+
help_text="Site being monitored",
|
688
|
+
on_delete=django.db.models.deletion.CASCADE,
|
689
|
+
related_name="monitoring_target",
|
690
|
+
to="django_cfg_maintenance.cloudflaresite",
|
691
|
+
),
|
692
|
+
),
|
693
|
+
],
|
694
|
+
options={
|
695
|
+
"verbose_name": "Monitoring Target",
|
696
|
+
"verbose_name_plural": "Monitoring Targets",
|
697
|
+
},
|
698
|
+
),
|
699
|
+
migrations.CreateModel(
|
700
|
+
name="HealthCheckResult",
|
701
|
+
fields=[
|
702
|
+
(
|
703
|
+
"id",
|
704
|
+
models.BigAutoField(
|
705
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
706
|
+
),
|
707
|
+
),
|
708
|
+
(
|
709
|
+
"timestamp",
|
710
|
+
models.DateTimeField(
|
711
|
+
default=django.utils.timezone.now, help_text="When the check was performed"
|
712
|
+
),
|
713
|
+
),
|
714
|
+
("success", models.BooleanField(help_text="Whether the check was successful")),
|
715
|
+
(
|
716
|
+
"status_code",
|
717
|
+
models.PositiveIntegerField(
|
718
|
+
blank=True, help_text="HTTP response status code", null=True
|
719
|
+
),
|
720
|
+
),
|
721
|
+
(
|
722
|
+
"response_time_ms",
|
723
|
+
models.PositiveIntegerField(
|
724
|
+
blank=True, help_text="Response time in milliseconds", null=True
|
725
|
+
),
|
726
|
+
),
|
727
|
+
(
|
728
|
+
"response_size_bytes",
|
729
|
+
models.PositiveIntegerField(
|
730
|
+
blank=True, help_text="Response size in bytes", null=True
|
731
|
+
),
|
732
|
+
),
|
733
|
+
(
|
734
|
+
"error_message",
|
735
|
+
models.TextField(blank=True, help_text="Error message if check failed"),
|
736
|
+
),
|
737
|
+
(
|
738
|
+
"error_type",
|
739
|
+
models.CharField(
|
740
|
+
blank=True,
|
741
|
+
help_text="Type of error (timeout, connection, etc.)",
|
742
|
+
max_length=100,
|
743
|
+
),
|
744
|
+
),
|
745
|
+
(
|
746
|
+
"details",
|
747
|
+
models.JSONField(
|
748
|
+
blank=True,
|
749
|
+
default=dict,
|
750
|
+
help_text="Additional check details (headers, content, etc.)",
|
751
|
+
),
|
752
|
+
),
|
753
|
+
(
|
754
|
+
"target",
|
755
|
+
models.ForeignKey(
|
756
|
+
help_text="Monitoring target this result belongs to",
|
757
|
+
on_delete=django.db.models.deletion.CASCADE,
|
758
|
+
related_name="results",
|
759
|
+
to="django_cfg_maintenance.monitoringtarget",
|
760
|
+
),
|
761
|
+
),
|
762
|
+
],
|
763
|
+
options={
|
764
|
+
"verbose_name": "Health Check Result",
|
765
|
+
"verbose_name_plural": "Health Check Results",
|
766
|
+
"ordering": ["-timestamp"],
|
767
|
+
},
|
768
|
+
),
|
769
|
+
migrations.CreateModel(
|
770
|
+
name="SiteGroup",
|
771
|
+
fields=[
|
772
|
+
(
|
773
|
+
"id",
|
774
|
+
models.BigAutoField(
|
775
|
+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
776
|
+
),
|
777
|
+
),
|
778
|
+
("name", models.CharField(help_text="Group name", max_length=100)),
|
779
|
+
("description", models.TextField(blank=True, help_text="Group description")),
|
780
|
+
(
|
781
|
+
"auto_maintenance_rules",
|
782
|
+
models.JSONField(
|
783
|
+
blank=True,
|
784
|
+
default=dict,
|
785
|
+
help_text="Automatic maintenance rules for this group",
|
786
|
+
),
|
787
|
+
),
|
788
|
+
(
|
789
|
+
"notification_settings",
|
790
|
+
models.JSONField(
|
791
|
+
blank=True,
|
792
|
+
default=dict,
|
793
|
+
help_text="Notification preferences for group events",
|
794
|
+
),
|
795
|
+
),
|
796
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
797
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
798
|
+
(
|
799
|
+
"owner",
|
800
|
+
models.ForeignKey(
|
801
|
+
help_text="Group owner",
|
802
|
+
on_delete=django.db.models.deletion.CASCADE,
|
803
|
+
to=settings.AUTH_USER_MODEL,
|
804
|
+
),
|
805
|
+
),
|
806
|
+
(
|
807
|
+
"sites",
|
808
|
+
models.ManyToManyField(
|
809
|
+
help_text="Sites in this group",
|
810
|
+
related_name="groups",
|
811
|
+
to="django_cfg_maintenance.cloudflaresite",
|
812
|
+
),
|
813
|
+
),
|
814
|
+
],
|
815
|
+
options={
|
816
|
+
"verbose_name": "Site Group",
|
817
|
+
"verbose_name_plural": "Site Groups",
|
818
|
+
"ordering": ["name"],
|
819
|
+
},
|
820
|
+
),
|
821
|
+
migrations.AddIndex(
|
822
|
+
model_name="cloudflaresite",
|
823
|
+
index=models.Index(
|
824
|
+
fields=["owner", "environment"], name="django_cfg__owner_i_5d4060_idx"
|
825
|
+
),
|
826
|
+
),
|
827
|
+
migrations.AddIndex(
|
828
|
+
model_name="cloudflaresite",
|
829
|
+
index=models.Index(
|
830
|
+
fields=["project", "environment"], name="django_cfg__project_9a07f1_idx"
|
831
|
+
),
|
832
|
+
),
|
833
|
+
migrations.AddIndex(
|
834
|
+
model_name="cloudflaresite",
|
835
|
+
index=models.Index(fields=["current_status"], name="django_cfg__current_fcca20_idx"),
|
836
|
+
),
|
837
|
+
migrations.AddIndex(
|
838
|
+
model_name="cloudflaresite",
|
839
|
+
index=models.Index(
|
840
|
+
fields=["maintenance_active"], name="django_cfg__mainten_0c725d_idx"
|
841
|
+
),
|
842
|
+
),
|
843
|
+
migrations.AddIndex(
|
844
|
+
model_name="cloudflaresite",
|
845
|
+
index=models.Index(fields=["domain"], name="django_cfg__domain_179845_idx"),
|
846
|
+
),
|
847
|
+
migrations.AddIndex(
|
848
|
+
model_name="maintenanceevent",
|
849
|
+
index=models.Index(
|
850
|
+
fields=["status", "-started_at"], name="django_cfg__status_a7d5f3_idx"
|
851
|
+
),
|
852
|
+
),
|
853
|
+
migrations.AddIndex(
|
854
|
+
model_name="maintenanceevent",
|
855
|
+
index=models.Index(
|
856
|
+
fields=["reason", "-started_at"], name="django_cfg__reason_214648_idx"
|
857
|
+
),
|
858
|
+
),
|
859
|
+
migrations.AddIndex(
|
860
|
+
model_name="maintenanceevent",
|
861
|
+
index=models.Index(
|
862
|
+
fields=["initiated_by", "-started_at"], name="django_cfg__initiat_7ad0ad_idx"
|
863
|
+
),
|
864
|
+
),
|
865
|
+
migrations.AddIndex(
|
866
|
+
model_name="cloudflaredeployment",
|
867
|
+
index=models.Index(
|
868
|
+
fields=["site", "-created_at"], name="django_cfg__site_id_7414e8_idx"
|
869
|
+
),
|
870
|
+
),
|
871
|
+
migrations.AddIndex(
|
872
|
+
model_name="cloudflaredeployment",
|
873
|
+
index=models.Index(
|
874
|
+
fields=["status", "-created_at"], name="django_cfg__status_ee1f80_idx"
|
875
|
+
),
|
876
|
+
),
|
877
|
+
migrations.AddIndex(
|
878
|
+
model_name="cloudflaredeployment",
|
879
|
+
index=models.Index(
|
880
|
+
fields=["deployment_type", "-created_at"], name="django_cfg__deploym_bc24ff_idx"
|
881
|
+
),
|
882
|
+
),
|
883
|
+
migrations.AddIndex(
|
884
|
+
model_name="cloudflaredeployment",
|
885
|
+
index=models.Index(fields=["resource_id"], name="django_cfg__resourc_fab8ca_idx"),
|
886
|
+
),
|
887
|
+
migrations.AddIndex(
|
888
|
+
model_name="maintenancelog",
|
889
|
+
index=models.Index(
|
890
|
+
fields=["event", "-timestamp"], name="django_cfg__event_i_b03d81_idx"
|
891
|
+
),
|
892
|
+
),
|
893
|
+
migrations.AddIndex(
|
894
|
+
model_name="maintenancelog",
|
895
|
+
index=models.Index(fields=["level", "-timestamp"], name="django_cfg__level_b66e18_idx"),
|
896
|
+
),
|
897
|
+
migrations.AddIndex(
|
898
|
+
model_name="maintenancelog",
|
899
|
+
index=models.Index(
|
900
|
+
fields=["component", "-timestamp"], name="django_cfg__compone_35dbe4_idx"
|
901
|
+
),
|
902
|
+
),
|
903
|
+
migrations.AddIndex(
|
904
|
+
model_name="monitoringtarget",
|
905
|
+
index=models.Index(
|
906
|
+
fields=["status", "last_check_at"], name="django_cfg__status_e57085_idx"
|
907
|
+
),
|
908
|
+
),
|
909
|
+
migrations.AddIndex(
|
910
|
+
model_name="monitoringtarget",
|
911
|
+
index=models.Index(
|
912
|
+
fields=["site", "-last_check_at"], name="django_cfg__site_id_37651c_idx"
|
913
|
+
),
|
914
|
+
),
|
915
|
+
migrations.AddIndex(
|
916
|
+
model_name="healthcheckresult",
|
917
|
+
index=models.Index(
|
918
|
+
fields=["target", "-timestamp"], name="django_cfg__target__1a3262_idx"
|
919
|
+
),
|
920
|
+
),
|
921
|
+
migrations.AddIndex(
|
922
|
+
model_name="healthcheckresult",
|
923
|
+
index=models.Index(
|
924
|
+
fields=["success", "-timestamp"], name="django_cfg__success_6181d8_idx"
|
925
|
+
),
|
926
|
+
),
|
927
|
+
migrations.AddIndex(
|
928
|
+
model_name="healthcheckresult",
|
929
|
+
index=models.Index(fields=["-timestamp"], name="django_cfg__timesta_ba6784_idx"),
|
930
|
+
),
|
931
|
+
migrations.AddIndex(
|
932
|
+
model_name="sitegroup",
|
933
|
+
index=models.Index(fields=["owner", "name"], name="django_cfg__owner_i_6ba808_idx"),
|
934
|
+
),
|
935
|
+
migrations.AlterUniqueTogether(
|
936
|
+
name="sitegroup",
|
937
|
+
unique_together={("name", "owner")},
|
938
|
+
),
|
939
|
+
]
|