from flask import Flask, jsonify, request from flask_apscheduler import APScheduler from typing import Dict, Union import json, time, redis, yaml from Components import * # declare flask apps app = Flask(__name__) scheduler = APScheduler() ####################################################################### ### Settings Handler Functions ####################################################################### # default application setting variables app_settings = { "noisy_test" : False, "debug_output" : True, "log_output" : True, "secure_api" : True, "push_redis" : False, "run_background" : True, "update_frequency": 1 } with open('cosmostat_settings.yaml', 'r') as f: print("Loading cosmostat_settings file") cosmostat_settings = yaml.safe_load(f) print("...Done") # initialize system variables from settings file print("Checking for system var overrides") for setting in app_settings: if setting in cosmostat_settings: cosmos_setting = cosmostat_settings[setting] if app_settings["debug_output"]: print(f"{setting}: {cosmos_setting}") app_settings[setting] = cosmos_setting print("...Done") # this returns the docker gateway from the settings def docker_gateway_settings() -> str: return cosmostat_settings["docker_gateway"] # this returns the jenkins user that ran the pipeline def jenkins_user_settings() -> str: return cosmostat_settings["jenkins_user"] # this returns the ansible_hostname from setup def jenkins_hostname_settings() -> str: return cosmostat_settings["ansible_hostname"] # this returns the inventory_generation_timestamp def jenkins_inventory_generation_timestamp_settings() -> str: return cosmostat_settings["inventory_generation_timestamp"] def service_gateway_ip(): if cosmostat_settings["secure_api"]: return docker_gateway_settings() else: return "0.0.0.0" ####################################################################### ### Redis Functions ####################################################################### # Redis client - will publish updates r = redis.Redis(host=service_gateway_ip(), port=6379) def update_redis_channel(redis_channel, data): # Publish to the specified Redis channel r.publish(redis_channel, json.dumps(data)) if app_settings["noisy_test"]: print(f"{redis_channel} Redis Update") print(data) def update_redis_server(): # Update Stats Redis Channel if cosmostat_system.check_system_timer(): update_redis_channel("host_metrics", get_redis_data(human_readable = False)) # Update history_stats Redis Channel # update_redis_channel("history_stats", get_component_list()) ####################################################################### ### Flask Routes ####################################################################### # dynamic data # this will go to the redis server @app.route('/dynamic_data', methods=['GET']) def dynamic_data(): return jsonify(get_dynamic_data()) # static data @app.route('/static_data', methods=['GET']) def static_data(): return jsonify(get_static_data()) # redis data @app.route('/redis_data', methods=['GET']) def redis_data(): return jsonify(get_redis_data(human_readable = False)) # redis strings @app.route('/redis_strings', methods=['GET']) def redis_strings(): return jsonify(get_redis_data(human_readable = True)) # full summary @app.route('/full_summary', methods=['GET']) def full_summary(): return jsonify(get_full_summary()) # php summary @app.route('/php_summary', methods=['GET']) def php_summary(): return jsonify(get_php_summary()) # system info @app.route('/info', methods=['GET']) def info(): return jsonify(get_info()) # socket timer @app.route('/start_timer', methods=['GET']) def start_timer(): current_timestamp = int(time.time()) cosmostat_system.recent_check = current_timestamp if app_settings["noisy_test"]: print(f"Timestamp updated to {cosmostat_system.recent_check}") return jsonify( { "message": "websocket timer reset", "new_timestamp": cosmostat_system.recent_check } ) # socket timer data @app.route('/timer_data', methods=['GET']) def timer_data(): time_now = time.time() time_lapsed = time_now - float(cosmostat_system.recent_check) result = { "Time Lapsed": time_lapsed, "Current Time Value": time_now, "Last Update Value": float(cosmostat_system.recent_check), "System Updating": cosmostat_system.check_system_timer() } return jsonify(result) # test route @app.route('/test', methods=['GET']) def test(): this_cpu = cosmostat_system.get_components(component_type="CPU") return jsonify( { "component_count:": len(cosmostat_system.components), "user": jenkins_user_settings(), "hostname": jenkins_hostname_settings(), "cpu_model": this_cpu[0].description } ) ####################################################################### ### Flask Helpers ####################################################################### # needs to return array of {name: name, type: type, metrics: metrics} # for redis table generation, includes system and component metrics def get_dynamic_data(human_readable = False): return cosmostat_system.get_live_metrics(human_readable) def get_static_data(human_readable = False): result = [] return cosmostat_system.get_static_metrics(human_readable) # php is about to start rendering static data def get_redis_data(human_readable = False): result = [] for metric in get_dynamic_data(human_readable): result.append(metric) #for metric in get_static_data(human_readable): # result.append(metric) return result def get_full_summary(): live_metrics = cosmostat_system.get_live_metrics() system_components = cosmostat_system.get_component_strings() system_info = get_info() result = { "system_settings": { "user": jenkins_user_settings(), "hostname": jenkins_hostname_settings(), "timestamp": jenkins_inventory_generation_timestamp_settings(), "component_count:": len(cosmostat_system.components), "object_name": cosmostat_system.name, "docker_gateway": docker_gateway_settings() }, "live_metrics": live_metrics, "system_components": system_components, "system_info": system_info } return result def get_info(): component_strings = [] for component in cosmostat_system.get_components(): component_strings.append({"name": component.name, "description": component.description}) result = { "hostname": jenkins_hostname_settings(), "component_strings": component_strings, "system_strings": cosmostat_system.get_sysvars_summary_keys() } #for component_string in component_strings: # for name, description in component_string.items(): # result[name] = description return result def get_php_summary(): system_properties = cosmostat_system.get_system_properties(human_readable = True) system_components = [] for component in cosmostat_system.get_components(): this_component = { "component_name": component.name, "info_strings": component.get_properties_strings(return_simple = True) } system_components.append(this_component) result = [{ "system_properties": system_properties, "system_components": system_components }] return result ####################################################################### ### Other Functions ####################################################################### # instantiate and return the System object def new_cosmos_system(): new_system = System(f"{jenkins_hostname_settings()}") if app_settings["log_output"]: print(f"New system object name: {new_system.name} - {new_system.get_component_count()} components:") for component in new_system.components: print(component.description) return new_system # Background Loop Function def background_loop(): # Update all data on the System object if cosmostat_system.check_system_timer(): cosmostat_system.update_system_state() if app_settings["push_redis"]: update_redis_server() if app_settings["noisy_test"]: print("Sorry about the mess...") print(f"Blame {jenkins_user_settings()}") ####################################################################### ### Main Subroutine ####################################################################### if __name__ == '__main__': # instantiate system cosmostat_system = new_cosmos_system() # send initial stats update to redis if app_settings["push_redis"]: update_redis_server() # Flask scheduler for scanner if app_settings["run_background"]: if app_settings["log_output"]: print("Loading flask background subroutine...") scheduler.add_job(id='background_loop', func=background_loop, trigger='interval', seconds=app_settings["update_frequency"]) scheduler.init_app(app) scheduler.start() if app_settings["log_output"]: print("...Done") else: if app_settings["log_output"]: print("Skipping flask background task") # Flask API app.run(debug=False, host=service_gateway_ip(), port=5000)