Skip to content

Commit a8f5db4

Browse files
authored
Merge pull request #2 from mohamedtaee/dev
Added feature to restart nginx container
2 parents e6fca52 + a5342f2 commit a8f5db4

File tree

6 files changed

+206
-11
lines changed

6 files changed

+206
-11
lines changed

app/api/endpoints.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
import io
33
import os
44
import flask
5+
import platform
6+
import docker
57

68
bp = flask.Blueprint('api', __name__, url_prefix='/api')
79

810

9-
@bp.route('/config/<name>', methods=['GET'])
11+
@bp.route('/config/<name>', methods=['GET'])
1012
def get_config(name: str):
1113
"""
1214
Reads the file with the corresponding name that was passed.
@@ -215,3 +217,46 @@ def enable_domain(name: str):
215217
os.rename(os.path.join(config_path, _), os.path.join(config_path, _ + '.disabled'))
216218

217219
return flask.make_response({'success': True}), 200
220+
221+
222+
def is_rhel():
223+
try:
224+
with open('/etc/os-release') as f:
225+
os_release = f.read()
226+
return 'rhel' in os_release.lower()
227+
except FileNotFoundError:
228+
return False
229+
230+
231+
USE_SUDO_PODMAN = is_rhel()
232+
233+
234+
def get_docker_client():
235+
print("Platform: ", platform.system())
236+
if USE_SUDO_PODMAN:
237+
base_url = f'unix:///run/user/{os.getuid()}/podman/podman.sock'
238+
elif platform.system() == "Windows":
239+
base_url = 'npipe:////./pipe/docker_engine'
240+
else:
241+
base_url = 'unix://var/run/docker.sock'
242+
return docker.DockerClient(base_url=base_url)
243+
244+
245+
client = get_docker_client()
246+
247+
248+
@bp.route('/restart-nginx', methods=['POST'])
249+
def restart_nginx():
250+
try:
251+
container = client.containers.get('nginx')
252+
container.restart()
253+
except Exception as e:
254+
return flask.jsonify({"message": f"Error: {e}"}), 500
255+
return flask.jsonify({"message": "Nginx container restarted"}), 200
256+
257+
258+
@bp.route('/status-nginx', methods=['GET'])
259+
def status_nginx():
260+
container = client.containers.get('nginx')
261+
status = container.status
262+
return flask.jsonify({"container": "nginx", "status": status}), 200

app/static/custom.css

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,92 @@ textarea {
1414
#main-container {
1515
margin-top: 5em;
1616
}
17+
1718
#domain {
1819
display: none;
1920
}
2021

2122
@media only screen and (max-width: 666px) {
22-
[class*="mobile hidden"],
23-
[class*="tablet only"]:not(.mobile),
24-
[class*="computer only"]:not(.mobile),
25-
[class*="large monitor only"]:not(.mobile),
26-
[class*="widescreen monitor only"]:not(.mobile),
27-
[class*="or lower hidden"] {
28-
display: none !important;
29-
}
30-
}
23+
[class*="mobile hidden"],
24+
[class*="tablet only"]:not(.mobile),
25+
[class*="computer only"]:not(.mobile),
26+
[class*="large monitor only"]:not(.mobile),
27+
[class*="widescreen monitor only"]:not(.mobile),
28+
[class*="or lower hidden"] {
29+
display: none !important;
30+
}
31+
}
32+
33+
.status-circle {
34+
display: inline-block;
35+
width: 10px;
36+
height: 10px;
37+
border-radius: 50%;
38+
margin-right: 5px;
39+
}
40+
41+
.status-running {
42+
background-color: limegreen;
43+
}
44+
45+
.status-exited {
46+
background-color: red;
47+
}
48+
49+
.status-loading {
50+
background-color: orange;
51+
}
52+
53+
.status-paused {
54+
background-color: grey;
55+
}
56+
57+
.status-black {
58+
background-color: black;
59+
}
60+
61+
.restart-button {
62+
margin-left: 10px;
63+
padding: 5px 10px;
64+
background-color: #007bff;
65+
color: white;
66+
border: none;
67+
border-radius: 3px;
68+
cursor: pointer;
69+
}
70+
71+
.restart-button:hover {
72+
background-color: #0056b3;
73+
}
74+
75+
@keyframes spin {
76+
0% {
77+
transform: rotate(0deg);
78+
}
79+
100% {
80+
transform: rotate(360deg);
81+
}
82+
}
83+
84+
.custom-spinner {
85+
display: inline-block;
86+
width: 2rem;
87+
height: 2rem;
88+
vertical-align: text-bottom;
89+
border: 0.25em solid currentColor;
90+
border-right-color: transparent;
91+
border-radius: 50%;
92+
animation: spin 0.75s linear infinite;
93+
}
94+
95+
.custom-spinner-sm {
96+
width: 1rem;
97+
height: 1rem;
98+
border-width: 0.2em;
99+
}
100+
101+
.custom-spinner-lg {
102+
width: 3rem;
103+
height: 3rem;
104+
border-width: 0.3em;
105+
}

app/static/nginxController.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
document.addEventListener('DOMContentLoaded', function () {
2+
setNginxStatusCircle();
3+
});
4+
5+
function setNginxStatusCircle() {
6+
const nginxStatusCircle = document.getElementById('nginx-status-circle');
7+
8+
fetch('/api/status-nginx')
9+
.then(response => response.json())
10+
.then(data => {
11+
console.log(data);
12+
13+
const containerStatus = data.status;
14+
console.log("Container status: " + containerStatus);
15+
nginxStatusCircle.className = 'status-circle status-' + containerStatus;
16+
return containerStatus;
17+
});
18+
}
19+
20+
let restartProcessComplete = true;
21+
22+
function restartStatusInterval() {
23+
const nginxStatusCircle = document.getElementById('nginx-status-circle');
24+
nginxStatusCircle.className = 'status-circle status-loading';
25+
26+
const intervalId = setInterval(() => {
27+
if (restartProcessComplete) {
28+
clearInterval(intervalId);
29+
setNginxStatusCircle();
30+
} else {
31+
if (nginxStatusCircle.className === 'status-circle status-loading') {
32+
nginxStatusCircle.className = 'status-circle status-black';
33+
} else {
34+
nginxStatusCircle.className = 'status-circle status-loading';
35+
}
36+
}
37+
}, 100);
38+
}
39+
40+
41+
function restartNginx() {
42+
restartProcessComplete = false;
43+
restartStatusInterval();
44+
45+
const restartBtn = document.getElementById('nginx-restart-btn');
46+
restartBtn.disabled = true;
47+
48+
const restartSpinner = document.getElementById('nginx-restart-btn-spinner');
49+
restartSpinner.className = 'custom-spinner custom-spinner-sm';
50+
51+
52+
fetch('/api/restart-nginx', {method: "POST"})
53+
.then(response => response.json())
54+
.then(data => {
55+
console.log(data);
56+
})
57+
.finally(() => {
58+
setNginxStatusCircle();
59+
restartProcessComplete = true;
60+
restartSpinner.className = '';
61+
restartBtn.disabled = false;
62+
});
63+
}

app/templates/index.html

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
{{ moment.include_moment() }}
1414
<script src="{{ url_for('static', filename='semantic.min.js') }}"></script>
1515
<script src="{{ url_for('static', filename='custom.min.js') }}"></script>
16+
<script src="{{ url_for('static', filename='nginxController.js') }}"></script>
1617
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='custom.css') }}">
1718
</head>
1819
<body>
@@ -40,6 +41,15 @@
4041
Domains
4142
</a>
4243

44+
<a class="item" id="nginx-status">
45+
<span class="status-circle status-loading" id="nginx-status-circle"></span>
46+
Nginx Status
47+
<button class="restart-button" style="margin-left: 10px" onclick="restartNginx()" id="nginx-restart-btn" type="button">
48+
<span class="" aria-hidden="true" id="nginx-restart-btn-spinner"></span>
49+
<span role="status">Restart</span>
50+
</button>
51+
</a>
52+
4353
<div class="mobile hidden right item">
4454
<div class="ui action input">
4555
<input type="text" placeholder="example.com" id="add_domain">

docker-compose.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ services:
88
- "8080:8080"
99
volumes:
1010
- nginx:/etc/nginx
11+
- /var/run/docker.sock:/var/run/docker.sock
1112

1213
nginx:
1314
container_name: nginx

requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
Flask~=3.0.3
22
gunicorn~=22.0.0
3-
Flask-Moment~=1.0.5
3+
Flask-Moment~=1.0.5
4+
docker~=7.1.0

0 commit comments

Comments
 (0)