408 lines
15 KiB
Python
408 lines
15 KiB
Python
from flask import Blueprint, request, jsonify, render_template, session
|
|
from User_Functions import *
|
|
from API_Functions import *
|
|
import data_types as attr_data_types
|
|
from Evaluation import perform_evaluation
|
|
from data_types import get_attr_data_type
|
|
import db.db_functions as db_functions
|
|
import os
|
|
import time
|
|
import get_data as file
|
|
import activemq
|
|
import traceback
|
|
import logging
|
|
# logging.disable(logging.CRITICAL)
|
|
|
|
main_routes = Blueprint('main', __name__)
|
|
|
|
# List of items with Ordinal Data
|
|
Ordinal_Variables = ['attr-reputation', 'attr-assurance']
|
|
NoData_Variables = ['attr-security', 'attr-performance-capacity', 'attr-performance-suitability']
|
|
Cont_Variables = ['attr-performance', 'attr-financial', 'attr-performance-capacity-memory',
|
|
'attr-performance-capacity-memory-speed']
|
|
|
|
dummy_node_data = {
|
|
"id": "8a7481d98e702b64018e702cbe070000",
|
|
"nodeCandidateType": "EDGE",
|
|
"jobIdForByon": "",
|
|
"jobIdForEdge": "FCRnewLight0",
|
|
"price": 0.0,
|
|
"cloud": {
|
|
"id": "edge",
|
|
"endpoint": "",
|
|
"cloudType": "EDGE",
|
|
"api": "",
|
|
"credential": "",
|
|
"cloudConfiguration": {
|
|
"nodeGroup": "",
|
|
"properties": {}
|
|
},
|
|
"owner": "EDGE",
|
|
"state": "",
|
|
"diagnostic": ""
|
|
},
|
|
"location": {
|
|
"id": "edge-location-KmVf4xDJKL7acBGc",
|
|
"name": "",
|
|
"providerId": "",
|
|
"locationScope": "",
|
|
"isAssignable": "",
|
|
"geoLocation": {
|
|
"city": "Warsaw",
|
|
"country": "Poland",
|
|
"latitude": 52.237049,
|
|
"longitude": 21.017532
|
|
},
|
|
"parent": "",
|
|
"state": "",
|
|
"owner": ""
|
|
},
|
|
"image": {
|
|
"id": "edge-image-KmVf4xDJKL7acBGc",
|
|
"name": "edge-image-name-UBUNTU-UNKNOWN",
|
|
"providerId": "",
|
|
"operatingSystem": {
|
|
"operatingSystemFamily": "UBUNTU",
|
|
"operatingSystemArchitecture": "UNKNOWN",
|
|
"operatingSystemVersion": 1804.00
|
|
},
|
|
"location": "",
|
|
"state": "",
|
|
"owner": ""
|
|
},
|
|
"hardware": {
|
|
"id": "edge-hardware-KmVf4xDJKL7acBGc",
|
|
"name": "",
|
|
"providerId": "",
|
|
"cores": 1,
|
|
"ram": 1,
|
|
"disk": 1.0,
|
|
"fpga": 0,
|
|
"location": "",
|
|
"state": "",
|
|
"owner": ""
|
|
},
|
|
"pricePerInvocation": 0.0,
|
|
"memoryPrice": 0.0,
|
|
"nodeId": "",
|
|
"environment": ""
|
|
}
|
|
|
|
|
|
#Used in HomePage.vue to save app_id and user_id
|
|
# @main_routes.route('/save_ids', methods=['POST'])
|
|
# def save_ids():
|
|
# data = request.json
|
|
# app_id = data.get('app_id')
|
|
# user_id = data.get('user_id')
|
|
# print("user_id:", user_id)
|
|
# # Respond back with a success message
|
|
# return jsonify({"message": "IDs received successfully.", "app_id": app_id, "user_id": user_id})
|
|
|
|
|
|
|
|
#Used in CriteriaSelection.vue
|
|
@main_routes.route('/get_hierarchical_category_list')
|
|
def get_hierarchical_category_list():
|
|
items_list = file.get_level_1_items() # Assume this function returns the list correctly
|
|
if items_list is not None:
|
|
# Return the list as a JSON response
|
|
return jsonify(items_list)
|
|
else:
|
|
# Return an empty list or an error message if items_list is None
|
|
return jsonify([]), 404 # or return jsonify({"error": "No items found"}), 404
|
|
|
|
# Used in DataGrid.vue
|
|
@main_routes.route('/process_selected_criteria', methods=['POST'])
|
|
def process_selected_criteria():
|
|
try:
|
|
data = request.json
|
|
selected_criteria = data.get('selectedItems', [])
|
|
|
|
# application_id = data.get('app_id')
|
|
# user_id = data.get('user_id')
|
|
# print("user_id:", user_id)
|
|
# print("application_id:", application_id)
|
|
|
|
message_for_SAL = [{
|
|
"type": "NodeTypeRequirement",
|
|
"nodeTypes": ["IAAS", "PAAS", "FAAS", "BYON", "EDGE", "SIMULATION"]}
|
|
# ,{
|
|
# "type": "AttributeRequirement",
|
|
# "requirementClass": "hardware",
|
|
# "requirementAttribute": "cores",
|
|
# "requirementOperator": "GEQ",
|
|
# "value": "64"
|
|
# },
|
|
# {
|
|
# "type": "AttributeRequirement",
|
|
# "requirementClass": "hardware",
|
|
# "requirementAttribute": "ram",
|
|
# "requirementOperator": "GEQ",
|
|
# "value": "33000"
|
|
# }
|
|
]
|
|
body_json_string_for_SAL = json.dumps(message_for_SAL)
|
|
|
|
RequestToSal = {
|
|
"metaData": {"user": "admin"},
|
|
"body": body_json_string_for_SAL
|
|
}
|
|
# print("RequestToSal:", RequestToSal)
|
|
|
|
sal_reply = activemq.call_publisher(RequestToSal)
|
|
nodes_data = json.loads(sal_reply) if isinstance(sal_reply, str) else sal_reply
|
|
# print("nodes_data", nodes_data)
|
|
|
|
extracted_data, node_ids, node_names = extract_SAL_node_candidate_data_Front(nodes_data)
|
|
# print("extracted_data:", extracted_data)
|
|
field_mapping = create_criteria_mapping()
|
|
# print("field_mapping", field_mapping)
|
|
|
|
default_list_criteria_mapping = {
|
|
# "Cost": "price",
|
|
"Operating cost": "price",
|
|
"Memory Price": "memoryPrice",
|
|
"Number of CPU Cores": "cores",
|
|
"Memory Size": "ram",
|
|
"Storage Capacity": "disk"
|
|
}
|
|
|
|
grid_data = {}
|
|
|
|
for node_data in extracted_data:
|
|
node_id = node_data.get('id')
|
|
# print("Before create_node_name")
|
|
node_name = create_node_name(node_data) if node_data else "Unknown"
|
|
# print("After create_node_name")
|
|
|
|
if node_id and node_id not in grid_data:
|
|
grid_data[node_id] = {"name": node_name, "criteria": []}
|
|
|
|
hardware_info = node_data.get('hardware', {}) # contains the values for criteria coming from SAL
|
|
|
|
for criterion_key in selected_criteria:
|
|
# print("criterion_key:", criterion_key)
|
|
criterion_info = file.get_subject_data(file.SMI_prefix + criterion_key) # It contains the titles of the criteria
|
|
# print("criterion_info:", criterion_info)
|
|
|
|
# Resolve title and then map title to field name
|
|
criterion_data_type = get_attr_data_type(criterion_key) # criterion_data_type: {'type': 1, 'values': ['Low', 'Medium', 'High']}
|
|
# print("criterion_data_type:", criterion_data_type)
|
|
criterion_title = criterion_info["title"]
|
|
|
|
# Fetch the values of the selected default criteria
|
|
if criterion_title in default_list_criteria_mapping:
|
|
SAL_criterion_name = field_mapping.get(criterion_title) # Map the criterion title with the criterion name in SAL's reply
|
|
value = hardware_info.get(SAL_criterion_name, "N/A") # Get the criterion values
|
|
else:
|
|
# Handle other criteria (this part may need adjustment based on your actual data structure)
|
|
# value = "N/A" # Placeholder for the logic to determine non-default criteria values
|
|
# Generate random or default values for rest criteria
|
|
type_value = criterion_data_type['type']
|
|
# print("type_value:", type_value)
|
|
|
|
if type_value == 1:
|
|
value = random.choice(["High", "Medium", "Low"])
|
|
elif type_value == 5:
|
|
value = random.choice(["True", "False"])
|
|
else:
|
|
value = round(random.uniform(1, 100), 2)
|
|
|
|
criterion_data = {
|
|
"title": criterion_title,
|
|
"value": value,
|
|
"data_type": criterion_data_type # criterion_data_type: {'type': 1, 'values': ['Low', 'Medium', 'High']}
|
|
}
|
|
grid_data[node_id]["criteria"].append(criterion_data)
|
|
|
|
grid_data_with_names = [{
|
|
'name': data["name"],
|
|
'id': node_id,
|
|
'criteria': data["criteria"]
|
|
} for node_id, data in grid_data.items()]
|
|
# print("grid_data_with_names:", grid_data_with_names)
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'gridData': grid_data_with_names,
|
|
'NodeNames': node_names
|
|
})
|
|
|
|
except Exception as e:
|
|
print(f"Error processing selected items: {e}")
|
|
return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
|
|
|
# Works by reading a JSON file with dummy data
|
|
# def process_selected_criteria():
|
|
# try:
|
|
# data = request.json
|
|
# # Selected Criteria by the User from the List
|
|
# selected_criteria = data.get('selectedItems', [])
|
|
# # Extract app_id, user_id
|
|
# application_id = data.get('app_id') # Take it from local storage from frontend
|
|
# # application_id = 'd535cf554ea66fbebfc415ac837a5828' #dummy application_id_optimizer
|
|
# user_id = data.get('user_id') # Take it from local storage from frontend
|
|
# print("user_id:", user_id)
|
|
# print("application_id:", application_id)
|
|
#
|
|
# ## Process SAL's Reply
|
|
# # extracted_data, number_of_nodes, node_names = extract_node_candidate_data('dummy_data_node_candidates.json')
|
|
# extracted_data, node_ids, node_names = extract_node_candidate_data('SAL_Response_11EdgeDevs.json')
|
|
# print("extracted_data:", extracted_data)
|
|
#
|
|
# # Use the create_criteria_mapping() to get the criteria mappings
|
|
# field_mapping = create_criteria_mapping(selected_criteria, extracted_data)
|
|
# grid_data = {name: [] for name in node_names}
|
|
#
|
|
# # Prepare the data to be sent to DataGrid.vue
|
|
# for node_data in extracted_data:
|
|
# node_name = node_data.get('name') # Using name to match
|
|
# node_id = node_data.get('id') # Extract the node ID
|
|
# grid_data[node_name] = {"id": node_id, "criteria": []}
|
|
#
|
|
# if node_name in grid_data: # Check if node_name exists in grid_data keys
|
|
# for item in selected_criteria:
|
|
# criterion_data = {}
|
|
# criterion_data["data_type"] = get_attr_data_type(item)
|
|
# item_data_dict = file.get_subject_data(file.SMI_prefix + item)
|
|
# criterion_data["title"] = item_data_dict["title"]
|
|
# field_name = field_mapping.get(criterion_data["title"], item)
|
|
#
|
|
# # Check if the field_name is a direct key or nested inside 'hardware'
|
|
# if field_name in node_data:
|
|
# value = node_data[field_name]
|
|
# elif 'hardware' in node_data and field_name in node_data['hardware']:
|
|
# value = node_data['hardware'][field_name]
|
|
# else:
|
|
# # Generate random or default values for unmapped criteria or missing data
|
|
# item_data_type_value = criterion_data["data_type"].get('type')
|
|
# if item_data_type_value == 1:
|
|
# value = random.choice(["High", "Medium", "Low"])
|
|
# elif item_data_type_value == 5:
|
|
# value = random.choice(["True", "False"])
|
|
# else:
|
|
# value = round(random.uniform(1, 100), 2)
|
|
#
|
|
# criterion_data["value"] = value if value != 0 else 0.00001
|
|
# # grid_data[node_id].append(criterion_data)
|
|
# grid_data[node_name]["criteria"].append(criterion_data)
|
|
#
|
|
# # Conversion to list format remains unchanged
|
|
# # grid_data_with_names = [{'name': name, 'criteria': data} for name, data in grid_data.items()]
|
|
# grid_data_with_names = [{'name': name, 'id': data["id"], 'criteria': data["criteria"]} for name, data in grid_data.items()]
|
|
# print("grid_data_with_names:", grid_data_with_names)
|
|
#
|
|
# # Send the comprehensive grid_data_with_names to the frontend
|
|
# return jsonify({
|
|
# 'success': True,
|
|
# 'gridData': grid_data_with_names,
|
|
# 'NodeNames': node_names
|
|
# })
|
|
# except Exception as e:
|
|
# print(f"Error processing selected items: {e}")
|
|
# traceback.print_exc()
|
|
# return jsonify({'success': False, 'error': str(e)}), 500
|
|
|
|
|
|
|
|
@main_routes.route('/process-evaluation-data', methods=['POST'])
|
|
def process_evaluation_data():
|
|
try:
|
|
data = request.get_json()
|
|
if data is None:
|
|
raise ValueError("Received data is not in JSON format or 'Content-Type' header is not set to 'application/json'")
|
|
|
|
# print("JSON in process_evaluation_data:", data)
|
|
# Transform grid data to table and get node names directly from the function
|
|
data_table, relative_wr_data, immediate_wr_data, node_names, node_ids = transform_grid_data_to_table(data)
|
|
|
|
# print("data_table FRONT:", data_table)
|
|
# print("relative_wr_data:", relative_wr_data)
|
|
# print("immediate_wr_data:", immediate_wr_data)
|
|
# print("# node_names:", len(node_names))
|
|
# print("# node_ids:", len(node_ids))
|
|
|
|
# Run Optimization - Perform evaluation
|
|
results = perform_evaluation(data_table, relative_wr_data, immediate_wr_data, node_names, node_ids)
|
|
# print(results)
|
|
# Return the results
|
|
return jsonify({'status': 'success', 'results': results})
|
|
|
|
except Exception as e:
|
|
error_message = str(e)
|
|
return jsonify({'status': 'error', 'message': error_message}), 500
|
|
|
|
|
|
#Creates a new user
|
|
@main_routes.route('/user', methods=['POST'])
|
|
def create_user():
|
|
data = request.json
|
|
result = db_functions.insert_user(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Used in front end to authenticate the user
|
|
@main_routes.route('/login', methods=['POST'])
|
|
def select_user():
|
|
data = request.json
|
|
result = db_functions.get_user(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Returns the user's apps
|
|
@main_routes.route('/apps', methods=['POST'])
|
|
def select_user_apps():
|
|
data = request.json
|
|
result = db_functions.get_user_apps(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Creates a new app in db
|
|
@main_routes.route('/app/create', methods=['POST'])
|
|
def create_app():
|
|
data = request.json
|
|
result = db_functions.insert_app(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Checks if app exists or inserts it in db
|
|
@main_routes.route('/app', methods=['POST'])
|
|
def check_for_app():
|
|
data = request.json
|
|
result = db_functions.get_app(data)
|
|
if not result:
|
|
data['title'] = "Demo App"
|
|
data['description'] = "Demo App description"
|
|
result = db_functions.insert_app(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Get app from db
|
|
@main_routes.route('/app/get', methods=['POST'])
|
|
def get_app():
|
|
data = request.json
|
|
result = db_functions.get_app(data)
|
|
return jsonify(result)
|
|
|
|
|
|
# Called by save project in .VUE
|
|
@main_routes.route('/app/save', methods=['POST'])
|
|
def save_app():
|
|
data = request.get_json()
|
|
result = save_app_data(data)
|
|
return result
|
|
|
|
|
|
# Emulate ActMQ functionality
|
|
@main_routes.route('/test_sender', methods=['POST'])
|
|
def send():
|
|
data = request.get_json()
|
|
body = data['body']
|
|
application_id = data['application_id']
|
|
correlation_id = data['correlation_id']
|
|
key = data['key']
|
|
sender = activemq.test_send(data)
|
|
return data
|