Files
flask_consul/main.py
2023-06-20 09:29:35 +03:00

193 lines
5.2 KiB
Python

import json
import random
from time import sleep
import uuid
import atexit
import os
import socket, struct
import requests
from flask import Flask
import time
import consul
from logging.config import dictConfig
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
}},
'handlers': {'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout',
'formatter': 'default'
}},
'root': {
'level': 'INFO',
'handlers': ['wsgi']
}
})
def convert_seconds(seconds):
if seconds > 0:
# generated by ChatGPT
days = seconds // (24 * 60 * 60)
seconds = seconds % (24 * 60 * 60)
hours = seconds // (60 * 60)
seconds = seconds % (60 * 60)
minutes = seconds // 60
seconds = seconds % 60
return (f"{days} days {hours} hours {minutes} minutes {seconds} seconds")
else:
return "never"
def get_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.settimeout(0)
try:
# doesn't even have to be reachable
s.connect(('10.254.254.254', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
def get_default_gateway_linux():
with open("/proc/net/route") as fh:
for line in fh:
fields = line.strip().split()
if fields[1] != '00000000' or not int(fields[3], 16) & 2:
continue
return socket.inet_ntoa(struct.pack("<L", int(fields[2], 16)))
if os.getenv('CONSUL') != None:
CONSUL = os.getenv('CONSUL')
else:
CONSUL=get_default_gateway_linux()
if os.getenv('HOSTNAME') != None:
HOSTNAME = os.getenv('HOSTNAME')
else:
HOSTNAME=get_ip()
BASE_CONSUL_URL = 'http://' + CONSUL + ':8500'
configuration = {
'default': {
'config' : {'default':'config'}
, 'time' : int(time.time())
}
, 'consul' :{
'config' : {}
, 'time': 0
, 'state': {
'status': ''
, 'time': 0
}
}
}
SERVICE_ADDRESS = get_ip()
PORT = 8080
UUID=str(uuid.uuid5(uuid.NAMESPACE_DNS, f'{SERVICE_ADDRESS}:{PORT}:{HOSTNAME}'))
c = consul.Consul(host=CONSUL)
app = Flask(__name__)
@app.route('/')
def home():
global configuration
message = f"Hello World, <br> I`m {HOSTNAME} from {SERVICE_ADDRESS} {PORT} {UUID} <br> my config: {configuration['default']['config']} |"
if configuration['consul']['config'] != configuration['default']['config']:
delta_time = convert_seconds(configuration['consul']['time']-configuration['default']['time'])
message += f"<br>configuration changed {delta_time} ago. new configuration: {configuration['consul']['config']} | default config: {configuration['default']['config']}"
else:
message += f'configuration NOT changed'
message += '<br>'
message += f"Consul request state: {configuration['consul']['state']['status']} was {convert_seconds(int(time.time()) - configuration['consul']['state']['time'])} ago"
message += f'<br> <!-- {configuration} -->'
return message
@app.route('/health')
def hello_world():
data = {
'status': 'healthy'
}
global configuration
try:
_, resp = c.kv.get('PythonApp/config', wait='2s')
configuration['consul'] = {
'config' : resp['Value']
, 'time': int(time.time())
, 'state': {
'status': 'OK'
, 'time': int(time.time())
}
}
except Exception as e:
configuration['consul']['state'] = {
'status': 'Failed to fetch'
, 'time': int(time.time())
}
# config = {}
app.logger.debug(f'Get config from consul failed: {e}')
return json.dumps(data)
@app.route('/register')
def register():
url = f'{BASE_CONSUL_URL}/v1/agent/service/register'
data = {
'Name': 'PythonApp',
'ID': UUID,
'Tags': ['flask'],
'Address': SERVICE_ADDRESS,
'Port': PORT,
'Check': {
'http': f'http://{SERVICE_ADDRESS}:{PORT}/health',
'interval': '10s'
}
}
res = requests.put(
url
, data=json.dumps(data)
, timeout=15
)
return res
def cleanup():
try:
sleep(int(random.randrange(1,5)))
url = f'{BASE_CONSUL_URL}/v1/agent/service/deregister/{UUID}'
data = {
'service_id': UUID,
}
res = requests.put(
url,
data=json.dumps(data)
)
app.logger.debug(f'Service registration parameters: {data} | {res.status_code} : {res.text}')
return f'Response: {res.text} | status_code: {res.status_code}'
except Exception as e:
app.logger.debug(f'{e}')
atexit.register(cleanup)
if __name__ == '__main__':
sleep(1)
status = ""
while status != 200:
try:
print(f'Registering on consul')
status = register().status_code
sleep(int(random.randrange(1,5)))
except Exception as e:
print(f'ERROR::::: {e}')
sleep(int(random.randrange(1,5)))
app.run(debug=True, host="0.0.0.0", port=PORT)