dbca-utils 3.0.2__tar.gz → 3.0.4__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.
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/PKG-INFO +21 -1
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/README.md +20 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/pyproject.toml +1 -1
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/healthcheck/healthcheck.py +103 -2
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/LICENSE +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/__init__.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/apps.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/healthcheck/__init__.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/healthcheck/urls.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/middleware.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/models.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/src/dbca_utils/utils.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/__init__.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/apps.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/migrations/0001_initial.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/migrations/__init__.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/models.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/settings.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/templates/tests/test_model_list.html +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/tests.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/urls.py +0 -0
- {dbca_utils-3.0.2 → dbca_utils-3.0.4}/tests/views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dbca-utils
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.4
|
|
4
4
|
Summary: Utilities for DBCA Django apps
|
|
5
5
|
Author-Email: Rocky Chen <rocky.chen@dbca.wa.gov.au>, Ashley Felton <ashley.felton@dbca.wa.gov.au>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -101,3 +101,23 @@ MIDDLEWARE = [
|
|
|
101
101
|
- `modifier` - FK to `AUTH_USER_MODEL`, used to record who the object was last modified by
|
|
102
102
|
- `created` - a timestamp that is set on initial object save
|
|
103
103
|
- `modified` - an auto-updating timestamp (on each object save)
|
|
104
|
+
|
|
105
|
+
## Healthcheck feature
|
|
106
|
+
### Requirements
|
|
107
|
+
- Django 5.2 or later
|
|
108
|
+
- Declared the default cache and also the cache is shared by all pod instances
|
|
109
|
+
- The image has the command 'ps' which is used to collect the cpu and memory data
|
|
110
|
+
|
|
111
|
+
### Usage
|
|
112
|
+
- Install the app 'dbca_utils' in INSTALLED_APPS
|
|
113
|
+
- Service Configuration
|
|
114
|
+
- HEALTHCHECK_ENABLED: Optional. enable/disable the healthcheck service. default is 'true'
|
|
115
|
+
- PROCESS_FILTER: Optional. find the web app related processes from command 'ps aux'. default is '| grep python'
|
|
116
|
+
- CACHE_PREFIX: Optional. used as the prefix of the cache key. default is ''
|
|
117
|
+
- PORT: Optional. The listening port of the web application. default is '8080'
|
|
118
|
+
- WORKLOADS: Optional. Used if the web app has a fixed replicas.
|
|
119
|
+
- WORKLOAD_DEPLOYMENT: Optional. the workload is deployment if it is true; otherwise it is statefulset. default is 'true'
|
|
120
|
+
- WORKLOAD_FAILED_THRESHOLD: Optional. The number of continuous failed times to treat a pod is offline.
|
|
121
|
+
- Nginx Configuration.
|
|
122
|
+
- Add a location 'location /healthcheck/' and configure it to use basic auth in nginx.
|
|
123
|
+
- Access the url : https://xxx.dbca.wa.gov.au/healthcheck/healthdata to get the health json data
|
|
@@ -73,3 +73,23 @@ MIDDLEWARE = [
|
|
|
73
73
|
- `modifier` - FK to `AUTH_USER_MODEL`, used to record who the object was last modified by
|
|
74
74
|
- `created` - a timestamp that is set on initial object save
|
|
75
75
|
- `modified` - an auto-updating timestamp (on each object save)
|
|
76
|
+
|
|
77
|
+
## Healthcheck feature
|
|
78
|
+
### Requirements
|
|
79
|
+
- Django 5.2 or later
|
|
80
|
+
- Declared the default cache and also the cache is shared by all pod instances
|
|
81
|
+
- The image has the command 'ps' which is used to collect the cpu and memory data
|
|
82
|
+
|
|
83
|
+
### Usage
|
|
84
|
+
- Install the app 'dbca_utils' in INSTALLED_APPS
|
|
85
|
+
- Service Configuration
|
|
86
|
+
- HEALTHCHECK_ENABLED: Optional. enable/disable the healthcheck service. default is 'true'
|
|
87
|
+
- PROCESS_FILTER: Optional. find the web app related processes from command 'ps aux'. default is '| grep python'
|
|
88
|
+
- CACHE_PREFIX: Optional. used as the prefix of the cache key. default is ''
|
|
89
|
+
- PORT: Optional. The listening port of the web application. default is '8080'
|
|
90
|
+
- WORKLOADS: Optional. Used if the web app has a fixed replicas.
|
|
91
|
+
- WORKLOAD_DEPLOYMENT: Optional. the workload is deployment if it is true; otherwise it is statefulset. default is 'true'
|
|
92
|
+
- WORKLOAD_FAILED_THRESHOLD: Optional. The number of continuous failed times to treat a pod is offline.
|
|
93
|
+
- Nginx Configuration.
|
|
94
|
+
- Add a location 'location /healthcheck/' and configure it to use basic auth in nginx.
|
|
95
|
+
- Access the url : https://xxx.dbca.wa.gov.au/healthcheck/healthdata to get the health json data
|
|
@@ -33,6 +33,18 @@ if WORKLOADS < 0 :
|
|
|
33
33
|
WORKLOADS = 0
|
|
34
34
|
WORKLOAD_FAILED_THRESHOLD = int(os.environ.get("WORKLOAD_FAILED_THRESHOLD",2))
|
|
35
35
|
|
|
36
|
+
WORKLOAD_VOLUMES = os.environ.get("WORKLOAD_VOLUMES","automatic")
|
|
37
|
+
|
|
38
|
+
if not WORKLOAD_VOLUMES or WORKLOAD_VOLUMES.lower() in ("disabled","false"):
|
|
39
|
+
WORKLOAD_VOLUMES_ENABLED = False
|
|
40
|
+
WORKLOAD_VOLUMES = None
|
|
41
|
+
elif WORKLOAD_VOLUMES.lower() == "automatic":
|
|
42
|
+
WORKLOAD_VOLUMES_ENABLED = True
|
|
43
|
+
WORKLOAD_VOLUMES = None
|
|
44
|
+
else:
|
|
45
|
+
WORKLOAD_VOLUMES = [v.strip() for v in WORKLOAD_VOLUMES.split(",") if v.strip()]
|
|
46
|
+
WORKLOAD_VOLUMES_ENABLED = True if WORKLOAD_VOLUMES else False
|
|
47
|
+
|
|
36
48
|
|
|
37
49
|
RANDOM_CHARS="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYA0123456789~!@#$%^&*()-_+=`{}[];':\",./<>?"
|
|
38
50
|
RANDOM_CHARS_MAX_INDEX = len(RANDOM_CHARS) - 1
|
|
@@ -104,10 +116,97 @@ def unregister_webappprocess():
|
|
|
104
116
|
logger.error("Failed to unregister the webapp process '{}({}).{}'.".format(hostname,ip,pid))
|
|
105
117
|
|
|
106
118
|
|
|
119
|
+
GET_VOLUMEUSAGE_CMD = None
|
|
120
|
+
def get_persistent_volumes_data():
|
|
121
|
+
global WORKLOAD_VOLUMES
|
|
122
|
+
global GET_VOLUMEUSAGE_CMD
|
|
123
|
+
try:
|
|
124
|
+
if WORKLOAD_VOLUMES == []:
|
|
125
|
+
return {}
|
|
126
|
+
elif GET_VOLUMEUSAGE_CMD:
|
|
127
|
+
cmd = GET_VOLUMEUSAGE_CMD
|
|
128
|
+
else:
|
|
129
|
+
if WORKLOAD_VOLUMES is None:
|
|
130
|
+
#not configured. should find them automatically,
|
|
131
|
+
#the detect logic is dedicated for kubenetes
|
|
132
|
+
cmd = 'df --output="source,target,size"'
|
|
133
|
+
result = subprocess.run(cmd,shell=True,capture_output=True,text=True)
|
|
134
|
+
volumes = []
|
|
135
|
+
datarow = False
|
|
136
|
+
volumesdata = {}
|
|
137
|
+
overlaysize = 0
|
|
138
|
+
for line in result.stdout.split("\n"):
|
|
139
|
+
line = line.strip()
|
|
140
|
+
if not line:
|
|
141
|
+
continue
|
|
142
|
+
if not datarow:
|
|
143
|
+
line = line.lower()
|
|
144
|
+
if line.startswith("filesystem") :
|
|
145
|
+
datarow = True
|
|
146
|
+
continue
|
|
147
|
+
source,target,size = line.split()
|
|
148
|
+
size = int(size)
|
|
149
|
+
source = source.lower()
|
|
150
|
+
if source == "overlay":
|
|
151
|
+
overlaysize = size
|
|
152
|
+
elif target.startswith("/dev/sd"):
|
|
153
|
+
volumesdata[targer] = size
|
|
154
|
+
for k,v in volumesdata.items():
|
|
155
|
+
if v == overlaysize:
|
|
156
|
+
#the volume is the same volume as overlay
|
|
157
|
+
continue
|
|
158
|
+
volumes.append(k)
|
|
159
|
+
|
|
160
|
+
WORKLOAD_VOLUMES = volumes
|
|
161
|
+
if volumes:
|
|
162
|
+
cmd = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
163
|
+
GET_VOLUMEUSAGE_CMD = cmd
|
|
164
|
+
else:
|
|
165
|
+
return {}
|
|
166
|
+
else:
|
|
167
|
+
volumes = WORKLOAD_VOLUMES
|
|
168
|
+
cmd = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
169
|
+
|
|
170
|
+
result = subprocess.run(cmd,shell=True,capture_output=True,text=True)
|
|
171
|
+
volumesdata = {}
|
|
172
|
+
datarow = False
|
|
173
|
+
for line in result.stdout.split("\n"):
|
|
174
|
+
line = line.strip()
|
|
175
|
+
if not line:
|
|
176
|
+
continue
|
|
177
|
+
if not datarow:
|
|
178
|
+
line = line.lower()
|
|
179
|
+
if line.startswith("mounted on") :
|
|
180
|
+
datarow = True
|
|
181
|
+
continue
|
|
182
|
+
target,size,used = line.split()
|
|
183
|
+
size = int(size[:-1])
|
|
184
|
+
used = int(used[:-1])
|
|
185
|
+
if size / 1048576 >= 10:
|
|
186
|
+
#large than 10G, use 'G' as unit
|
|
187
|
+
volumesdata[target] = {"size":size/1048576,"used":used / 1048576,"pcent":100 * used/size,"unit":"G"}
|
|
188
|
+
elif size / 1024 >= 10:
|
|
189
|
+
#large than 10M, use 'M' as unit
|
|
190
|
+
volumesdata[target] = {"size":size/1024,"used":used / 1024,"pcent":100 * used/size,"unit":"M"}
|
|
191
|
+
else:
|
|
192
|
+
volumesdata[target] = {"size":size,"used":used,"pcent":100 * used/size}
|
|
193
|
+
|
|
194
|
+
if not GET_VOLUMEUSAGE_CMD:
|
|
195
|
+
#This is the first time to get the volume usage, delete the non-exist volume from volumes
|
|
196
|
+
for i in range(len(volumes) - 1,-1,-1):
|
|
197
|
+
if volumes[i] not in volumesdata:
|
|
198
|
+
del volumes[i]
|
|
199
|
+
WORKLOAD_VOLUMES = volumes
|
|
200
|
+
GET_VOLUMEUSAGE_CMD = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
201
|
+
return volumesdata
|
|
202
|
+
except Exception as ex:
|
|
203
|
+
return "Failed to volumes usage data.{}: {}".format(ex.__class__.__name__,str(ex))
|
|
204
|
+
|
|
107
205
|
item_version = "__version__"
|
|
108
206
|
key_workloads = "{}__workloads__".format(CACHE_PREFIX)
|
|
109
207
|
key_workloads_lock = "{}lock__".format(key_workloads)
|
|
110
208
|
|
|
209
|
+
|
|
111
210
|
def register_webappserver(sender,environ,**kwargs):
|
|
112
211
|
"""
|
|
113
212
|
Register a web server running in the same workload
|
|
@@ -234,6 +333,8 @@ def get_workload_healthcheckdata():
|
|
|
234
333
|
if result["max_pmemory"] is None or result["max_pmemory"] < data[2]:
|
|
235
334
|
result["max_pmemory"] = data[2]
|
|
236
335
|
|
|
336
|
+
if WORKLOAD_VOLUMES_ENABLED:
|
|
337
|
+
result["volumes"] = get_persistent_volumes_data()
|
|
237
338
|
return (200,result)
|
|
238
339
|
|
|
239
340
|
bearer_token_re = re.compile("^Bearer\\s+(?P<token>\\S+)\\s*$")
|
|
@@ -284,7 +385,7 @@ def save_workloads(workloads,unreached_servers=None):
|
|
|
284
385
|
workloads[item_version] += 1
|
|
285
386
|
|
|
286
387
|
#save the new workloads data
|
|
287
|
-
cache.set(key_workloads,workloads)
|
|
388
|
+
cache.set(key_workloads,workloads,timeout=None)
|
|
288
389
|
logger.debug("Successfully save the workloads:{}".format(str_workloads(workloads)))
|
|
289
390
|
return
|
|
290
391
|
finally:
|
|
@@ -325,7 +426,7 @@ def save_assignedworkloads(assignedworkloads):
|
|
|
325
426
|
assignedworkloads[item_version] += 1
|
|
326
427
|
|
|
327
428
|
#save the new workloads data
|
|
328
|
-
cache.set(key_assignedworkloads,assignedworkloads)
|
|
429
|
+
cache.set(key_assignedworkloads,assignedworkloads,timeout=None)
|
|
329
430
|
logger.debug("Successfully save the assigned workloads:{}".format(assignedworkloads))
|
|
330
431
|
return
|
|
331
432
|
finally:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|