pulumi-django-azure 1.0.32__tar.gz → 1.0.34__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 (19) hide show
  1. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/PKG-INFO +4 -4
  2. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/pyproject.toml +8 -8
  3. pulumi_django_azure-1.0.34/src/pulumi_django_azure/azure_helper.py +78 -0
  4. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/middleware.py +18 -16
  5. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure.egg-info/PKG-INFO +4 -4
  6. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure.egg-info/requires.txt +3 -3
  7. pulumi_django_azure-1.0.32/src/pulumi_django_azure/azure_helper.py +0 -114
  8. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/README.md +0 -0
  9. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/setup.cfg +0 -0
  10. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/__init__.py +0 -0
  11. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/context_processors.py +0 -0
  12. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/django_deployment.py +0 -0
  13. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/management/commands/__init__.py +0 -0
  14. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/management/commands/purge_cache.py +0 -0
  15. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/management/commands/purge_cdn.py +0 -0
  16. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure/settings.py +0 -0
  17. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure.egg-info/SOURCES.txt +0 -0
  18. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure.egg-info/dependency_links.txt +0 -0
  19. {pulumi_django_azure-1.0.32 → pulumi_django_azure-1.0.34}/src/pulumi_django_azure.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulumi-django-azure
3
- Version: 1.0.32
3
+ Version: 1.0.34
4
4
  Summary: Simply deployment of Django on Azure with Pulumi
5
5
  Author-email: Maarten Ureel <maarten@youreal.eu>
6
6
  License-Expression: MIT
@@ -19,10 +19,10 @@ Requires-Dist: django-azure-communication-email<2.0.0,>=1.3.2
19
19
  Requires-Dist: django-environ<0.13.0,>=0.12.0
20
20
  Requires-Dist: django-redis<6.0.0,>=5.4.0
21
21
  Requires-Dist: django-storages[azure]<2.0.0,>=1.14.6
22
- Requires-Dist: pulumi>=3.165.0
22
+ Requires-Dist: pulumi>=3.166.0
23
23
  Requires-Dist: pulumi-azure-native>=3.2.0
24
- Requires-Dist: pulumi-random>=4.18.1
25
- Requires-Dist: redis[hiredis]<6.0.0,>=5.2.1
24
+ Requires-Dist: pulumi-random>=4.18.2
25
+ Requires-Dist: redis[hiredis]<7.0.0,>=6.0.0
26
26
 
27
27
  # Pulumi Django Deployment
28
28
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pulumi-django-azure"
7
- version = "1.0.32"
7
+ version = "1.0.34"
8
8
  description = "Simply deployment of Django on Azure with Pulumi"
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Maarten Ureel", email = "maarten@youreal.eu" }]
@@ -24,10 +24,10 @@ dependencies = [
24
24
  "django-environ (>=0.12.0,<0.13.0)",
25
25
  "django-redis (>=5.4.0,<6.0.0)",
26
26
  "django-storages[azure] (>=1.14.6,<2.0.0)",
27
- "pulumi (>=3.165.0)",
27
+ "pulumi (>=3.166.0)",
28
28
  "pulumi-azure-native (>=3.2.0)",
29
- "pulumi-random (>=4.18.1)",
30
- "redis[hiredis] (>=5.2.1,<6.0.0)"
29
+ "pulumi-random (>=4.18.2)",
30
+ "redis[hiredis] (>=6.0.0,<7.0.0)"
31
31
  ]
32
32
  requires-python = ">=3.11,<3.14"
33
33
 
@@ -36,7 +36,7 @@ Homepage = "https://gitlab.com/MaartenUreel/pulumi-django-azure"
36
36
 
37
37
  [tool.poetry]
38
38
  name = "pulumi-django-azure"
39
- version = "1.0.32"
39
+ version = "1.0.34"
40
40
  description = "Simplify deployment of Django websites on Azure with Pulumi"
41
41
  authors = ["Maarten Ureel <maarten@youreal.eu>"]
42
42
 
@@ -51,10 +51,10 @@ django-azure-communication-email = "^1.3.2"
51
51
  django-environ = "^0.12.0"
52
52
  django-redis = "^5.4.0"
53
53
  django-storages = {extras = ["azure"], version = "^1.14.6"}
54
- pulumi = ">=3.165.0"
54
+ pulumi = ">=3.166.0"
55
55
  pulumi-azure-native = ">=3.2.0"
56
- pulumi-random = ">=4.18.1"
57
- redis = {extras = ["hiredis"], version = "^5.2.1"}
56
+ pulumi-random = ">=4.18.2"
57
+ redis = {extras = ["hiredis"], version = "^6.0.0"}
58
58
 
59
59
  [tool.poetry.group.dev.dependencies]
60
60
  build = "^1.2.2.post1"
@@ -0,0 +1,78 @@
1
+ import base64
2
+ import json
3
+ import logging
4
+ import os
5
+ from dataclasses import dataclass
6
+ from subprocess import check_output
7
+
8
+ from azure.identity import DefaultAzureCredential
9
+ from azure.mgmt.resource import SubscriptionClient
10
+ from azure.mgmt.resource.subscriptions.models import Subscription
11
+
12
+ logger = logging.getLogger("pulumi_django_azure.azure_helper")
13
+
14
+
15
+ # Azure credentials
16
+ AZURE_CREDENTIAL = DefaultAzureCredential()
17
+
18
+ # Get the local IP addresses of the machine (only when runnig on Azure)
19
+ if os.environ.get("IS_AZURE_ENVIRONMENT"):
20
+ LOCAL_IP_ADDRESSES = check_output(["hostname", "--all-ip-addresses"]).decode("utf-8").strip().split(" ")
21
+ else:
22
+ LOCAL_IP_ADDRESSES = []
23
+
24
+
25
+ def get_db_password() -> str:
26
+ """
27
+ Get a valid password for the database.
28
+ """
29
+ token = AZURE_CREDENTIAL.get_token("https://ossrdbms-aad.database.windows.net/.default")
30
+
31
+ logger.debug("New database token: %s", token)
32
+
33
+ return token.token
34
+
35
+
36
+ @dataclass
37
+ class RedisCredentials:
38
+ username: str
39
+ password: str
40
+
41
+
42
+ def get_redis_credentials() -> RedisCredentials:
43
+ """
44
+ Get valid credentials for the Redis cache.
45
+ """
46
+ token = AZURE_CREDENTIAL.get_token("https://redis.azure.com/.default")
47
+
48
+ logger.debug("New Redis token: %s", token)
49
+
50
+ return RedisCredentials(_extract_username_from_token(token.token), token.token)
51
+
52
+
53
+ def get_subscription() -> Subscription:
54
+ """
55
+ Get the subscription for the current user.
56
+ """
57
+ subscription_client = SubscriptionClient(AZURE_CREDENTIAL)
58
+ subscriptions = list(subscription_client.subscriptions.list())
59
+ return subscriptions[0]
60
+
61
+
62
+ def _extract_username_from_token(token: str) -> str:
63
+ """
64
+ Extract the username from the JSON Web Token (JWT) token.
65
+ """
66
+ parts = token.split(".")
67
+ base64_str = parts[1]
68
+
69
+ if len(base64_str) % 4 == 2:
70
+ base64_str += "=="
71
+ elif len(base64_str) % 4 == 3:
72
+ base64_str += "="
73
+
74
+ json_bytes = base64.b64decode(base64_str)
75
+ json_str = json_bytes.decode("utf-8")
76
+ jwt = json.loads(json_str)
77
+
78
+ return jwt["oid"]
@@ -8,7 +8,7 @@ from django.db.utils import OperationalError
8
8
  from django.http import HttpResponse
9
9
  from django_redis import get_redis_connection
10
10
 
11
- from .azure_helper import db_token_will_expire, get_db_password, get_redis_credentials, redis_token_will_expire
11
+ from .azure_helper import get_db_password, get_redis_credentials
12
12
 
13
13
  logger = logging.getLogger("pulumi_django_azure.health_check")
14
14
 
@@ -27,25 +27,30 @@ class HealthCheckMiddleware:
27
27
  # Update the database credentials if needed
28
28
  if settings.AZURE_DB_PASSWORD:
29
29
  try:
30
- if db_token_will_expire():
31
- logger.debug("Database token will expire, fetching new credentials")
32
- settings.DATABASES["default"]["PASSWORD"] = get_db_password()
30
+ current_db_password = settings.DATABASES["default"]["PASSWORD"]
31
+ new_db_password = get_db_password()
32
+
33
+ if new_db_password != current_db_password:
34
+ logger.debug("Database password has changed, updating credentials")
35
+ settings.DATABASES["default"]["PASSWORD"] = new_db_password
36
+
37
+ # Close existing connections to force reconnect with new password
38
+ connection.close()
33
39
  else:
34
- logger.debug("Database token is still valid, skipping credentials update")
40
+ logger.debug("Database password unchanged, keeping existing credentials")
35
41
  except Exception as e:
36
42
  logger.error("Failed to update database credentials: %s", str(e))
37
-
38
43
  self._self_heal()
39
-
40
44
  return HttpResponse(status=503)
41
45
 
42
46
  # Update the Redis credentials if needed
43
47
  if settings.AZURE_REDIS_CREDENTIALS:
44
48
  try:
45
- if redis_token_will_expire():
46
- logger.debug("Redis token will expire, fetching new credentials")
49
+ current_redis_password = settings.CACHES["default"]["OPTIONS"]["PASSWORD"]
50
+ redis_credentials = get_redis_credentials()
47
51
 
48
- redis_credentials = get_redis_credentials()
52
+ if redis_credentials.password != current_redis_password:
53
+ logger.debug("Redis password has changed, updating credentials")
49
54
 
50
55
  # Re-authenticate the Redis connection
51
56
  redis_connection = get_redis_connection("default")
@@ -53,12 +58,10 @@ class HealthCheckMiddleware:
53
58
 
54
59
  settings.CACHES["default"]["OPTIONS"]["PASSWORD"] = redis_credentials.password
55
60
  else:
56
- logger.debug("Redis token is still valid, skipping credentials update")
61
+ logger.debug("Redis password unchanged, keeping existing credentials")
57
62
  except Exception as e:
58
63
  logger.error("Failed to update Redis credentials: %s", str(e))
59
-
60
64
  self._self_heal()
61
-
62
65
  return HttpResponse(status=503)
63
66
 
64
67
  try:
@@ -72,11 +75,10 @@ class HealthCheckMiddleware:
72
75
 
73
76
  return HttpResponse("OK")
74
77
 
75
- except OperationalError as e:
76
- logger.error("Database connection failed: %s", str(e))
77
- return HttpResponse(status=503)
78
78
  except Exception as e:
79
79
  logger.error("Health check failed with unexpected error: %s", str(e))
80
+ logger.warning("Self-healing by gracefully restarting workers.")
81
+ self._self_heal()
80
82
  return HttpResponse(status=503)
81
83
 
82
84
  return self.get_response(request)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pulumi-django-azure
3
- Version: 1.0.32
3
+ Version: 1.0.34
4
4
  Summary: Simply deployment of Django on Azure with Pulumi
5
5
  Author-email: Maarten Ureel <maarten@youreal.eu>
6
6
  License-Expression: MIT
@@ -19,10 +19,10 @@ Requires-Dist: django-azure-communication-email<2.0.0,>=1.3.2
19
19
  Requires-Dist: django-environ<0.13.0,>=0.12.0
20
20
  Requires-Dist: django-redis<6.0.0,>=5.4.0
21
21
  Requires-Dist: django-storages[azure]<2.0.0,>=1.14.6
22
- Requires-Dist: pulumi>=3.165.0
22
+ Requires-Dist: pulumi>=3.166.0
23
23
  Requires-Dist: pulumi-azure-native>=3.2.0
24
- Requires-Dist: pulumi-random>=4.18.1
25
- Requires-Dist: redis[hiredis]<6.0.0,>=5.2.1
24
+ Requires-Dist: pulumi-random>=4.18.2
25
+ Requires-Dist: redis[hiredis]<7.0.0,>=6.0.0
26
26
 
27
27
  # Pulumi Django Deployment
28
28
 
@@ -7,7 +7,7 @@ django-azure-communication-email<2.0.0,>=1.3.2
7
7
  django-environ<0.13.0,>=0.12.0
8
8
  django-redis<6.0.0,>=5.4.0
9
9
  django-storages[azure]<2.0.0,>=1.14.6
10
- pulumi>=3.165.0
10
+ pulumi>=3.166.0
11
11
  pulumi-azure-native>=3.2.0
12
- pulumi-random>=4.18.1
13
- redis[hiredis]<6.0.0,>=5.2.1
12
+ pulumi-random>=4.18.2
13
+ redis[hiredis]<7.0.0,>=6.0.0
@@ -1,114 +0,0 @@
1
- import base64
2
- import json
3
- import logging
4
- import os
5
- import time
6
- from dataclasses import dataclass
7
- from subprocess import check_output
8
-
9
- from azure.identity import DefaultAzureCredential
10
- from azure.mgmt.resource import SubscriptionClient
11
- from azure.mgmt.resource.subscriptions.models import Subscription
12
-
13
- _redis_token_cache = None
14
- _database_token_cache = None
15
-
16
- logger = logging.getLogger("pulumi_django_azure.azure_helper")
17
-
18
-
19
- # Azure credentials
20
- AZURE_CREDENTIAL = DefaultAzureCredential()
21
-
22
- # Get the local IP addresses of the machine (only when runnig on Azure)
23
- if os.environ.get("IS_AZURE_ENVIRONMENT"):
24
- LOCAL_IP_ADDRESSES = check_output(["hostname", "--all-ip-addresses"]).decode("utf-8").strip().split(" ")
25
- else:
26
- LOCAL_IP_ADDRESSES = []
27
-
28
-
29
- def get_db_password() -> str:
30
- """
31
- Get a valid password for the database.
32
- """
33
- global _database_token_cache
34
- _database_token_cache = AZURE_CREDENTIAL.get_token("https://ossrdbms-aad.database.windows.net/.default")
35
-
36
- logger.debug("New database token: %s", _database_token_cache)
37
-
38
- return _database_token_cache.token
39
-
40
-
41
- def db_token_will_expire(treshold=300) -> bool:
42
- """
43
- Check if the database token will expire in the next treshold seconds.
44
- """
45
- # If the token is not cached, we consider it expired (so a new one will be fetched)
46
- if _database_token_cache is None:
47
- return True
48
-
49
- logger.debug("Database token expires on: %s", _database_token_cache.expires_on)
50
-
51
- # If the token is cached, check if it will expire in the next treshold seconds
52
- return _database_token_cache.expires_on - time.time() < treshold
53
-
54
-
55
- @dataclass
56
- class RedisCredentials:
57
- username: str
58
- password: str
59
-
60
-
61
- def get_redis_credentials() -> RedisCredentials:
62
- """
63
- Get valid credentials for the Redis cache.
64
- """
65
- global _redis_token_cache
66
- _redis_token_cache = AZURE_CREDENTIAL.get_token("https://redis.azure.com/.default")
67
-
68
- t = _redis_token_cache.token
69
-
70
- logger.debug("New Redis token: %s", _redis_token_cache)
71
-
72
- return RedisCredentials(_extract_username_from_token(t), t)
73
-
74
-
75
- def redis_token_will_expire(treshold=300) -> bool:
76
- """
77
- Check if the Redis token will expire in the next treshold seconds.
78
- """
79
- # If the token is not cached, we consider it expired (so a new one will be fetched)
80
- if _redis_token_cache is None:
81
- return True
82
-
83
- logger.debug("Redis token expires on: %s", _redis_token_cache.expires_on)
84
-
85
- # If the token is cached, check if it will expire in the next treshold seconds
86
- return _redis_token_cache.expires_on - time.time() < treshold
87
-
88
-
89
- def get_subscription() -> Subscription:
90
- """
91
- Get the subscription for the current user.
92
- """
93
- subscription_client = SubscriptionClient(AZURE_CREDENTIAL)
94
- subscriptions = list(subscription_client.subscriptions.list())
95
- return subscriptions[0]
96
-
97
-
98
- def _extract_username_from_token(token: str) -> str:
99
- """
100
- Extract the username from the JSON Web Token (JWT) token.
101
- """
102
- parts = token.split(".")
103
- base64_str = parts[1]
104
-
105
- if len(base64_str) % 4 == 2:
106
- base64_str += "=="
107
- elif len(base64_str) % 4 == 3:
108
- base64_str += "="
109
-
110
- json_bytes = base64.b64decode(base64_str)
111
- json_str = json_bytes.decode("utf-8")
112
- jwt = json.loads(json_str)
113
-
114
- return jwt["oid"]