dbca-utils 3.0.3__tar.gz → 3.0.5__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.3 → dbca_utils-3.0.5}/PKG-INFO +21 -1
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/README.md +20 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/pyproject.toml +1 -1
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/healthcheck/healthcheck.py +105 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/LICENSE +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/__init__.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/apps.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/healthcheck/__init__.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/healthcheck/urls.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/middleware.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/models.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/src/dbca_utils/utils.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/__init__.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/apps.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/migrations/0001_initial.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/migrations/__init__.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/models.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/settings.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/templates/tests/test_model_list.html +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/tests.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/tests/urls.py +0 -0
- {dbca_utils-3.0.3 → dbca_utils-3.0.5}/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.5
|
|
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,101 @@ 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("//"):
|
|
153
|
+
volumes.append(target)
|
|
154
|
+
elif target.startswith("/dev/sd"):
|
|
155
|
+
#the volume can be same filesystem as the volume 'overlay'
|
|
156
|
+
volumesdata[target] = size
|
|
157
|
+
|
|
158
|
+
for k,v in volumesdata.items():
|
|
159
|
+
if v == overlaysize:
|
|
160
|
+
#the volume is the same volume as overlay
|
|
161
|
+
continue
|
|
162
|
+
volumes.append(k)
|
|
163
|
+
|
|
164
|
+
WORKLOAD_VOLUMES = volumes
|
|
165
|
+
if volumes:
|
|
166
|
+
cmd = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
167
|
+
GET_VOLUMEUSAGE_CMD = cmd
|
|
168
|
+
else:
|
|
169
|
+
return {}
|
|
170
|
+
else:
|
|
171
|
+
volumes = WORKLOAD_VOLUMES
|
|
172
|
+
cmd = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
173
|
+
|
|
174
|
+
result = subprocess.run(cmd,shell=True,capture_output=True,text=True)
|
|
175
|
+
volumesdata = {}
|
|
176
|
+
datarow = False
|
|
177
|
+
for line in result.stdout.split("\n"):
|
|
178
|
+
line = line.strip()
|
|
179
|
+
if not line:
|
|
180
|
+
continue
|
|
181
|
+
if not datarow:
|
|
182
|
+
line = line.lower()
|
|
183
|
+
if line.startswith("mounted on") :
|
|
184
|
+
datarow = True
|
|
185
|
+
continue
|
|
186
|
+
target,size,used = line.split()
|
|
187
|
+
size = int(size[:-1])
|
|
188
|
+
used = int(used[:-1])
|
|
189
|
+
if size / 1048576 >= 10:
|
|
190
|
+
#large than 10G, use 'G' as unit
|
|
191
|
+
volumesdata[target] = {"size":size/1048576,"used":used / 1048576,"pcent":100 * used/size,"unit":"G"}
|
|
192
|
+
elif size / 1024 >= 10:
|
|
193
|
+
#large than 10M, use 'M' as unit
|
|
194
|
+
volumesdata[target] = {"size":size/1024,"used":used / 1024,"pcent":100 * used/size,"unit":"M"}
|
|
195
|
+
else:
|
|
196
|
+
volumesdata[target] = {"size":size,"used":used,"pcent":100 * used/size}
|
|
197
|
+
|
|
198
|
+
if not GET_VOLUMEUSAGE_CMD:
|
|
199
|
+
#This is the first time to get the volume usage, delete the non-exist volume from volumes
|
|
200
|
+
for i in range(len(volumes) - 1,-1,-1):
|
|
201
|
+
if volumes[i] not in volumesdata:
|
|
202
|
+
del volumes[i]
|
|
203
|
+
WORKLOAD_VOLUMES = volumes
|
|
204
|
+
GET_VOLUMEUSAGE_CMD = 'df --output="target,size,used" -BK {}'.format(" ".join(volumes))
|
|
205
|
+
return volumesdata
|
|
206
|
+
except Exception as ex:
|
|
207
|
+
return "Failed to volumes usage data.{}: {}".format(ex.__class__.__name__,str(ex))
|
|
208
|
+
|
|
107
209
|
item_version = "__version__"
|
|
108
210
|
key_workloads = "{}__workloads__".format(CACHE_PREFIX)
|
|
109
211
|
key_workloads_lock = "{}lock__".format(key_workloads)
|
|
110
212
|
|
|
213
|
+
|
|
111
214
|
def register_webappserver(sender,environ,**kwargs):
|
|
112
215
|
"""
|
|
113
216
|
Register a web server running in the same workload
|
|
@@ -234,6 +337,8 @@ def get_workload_healthcheckdata():
|
|
|
234
337
|
if result["max_pmemory"] is None or result["max_pmemory"] < data[2]:
|
|
235
338
|
result["max_pmemory"] = data[2]
|
|
236
339
|
|
|
340
|
+
if WORKLOAD_VOLUMES_ENABLED:
|
|
341
|
+
result["volumes"] = get_persistent_volumes_data()
|
|
237
342
|
return (200,result)
|
|
238
343
|
|
|
239
344
|
bearer_token_re = re.compile("^Bearer\\s+(?P<token>\\S+)\\s*$")
|
|
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
|