"""Implementation of CloudSync controller""" import argparse import logging import socket import sys from flask import Flask, Response, request from flask_restplus import Api, Resource, fields, reqparse from cloudsync.utils.helpers import * from cloudsync.utils.globals import * from cloudsync.utils.reachability import ReachabilityProvider from cloudsync.busses.file_output_bus import FileOutputBus from cloudsync.handlers.cs_mft_dcs_request_handler import NetworkRequestHandler from cloudsync.handlers.ui_cs_request_handler import UICSMessageHandler from cloudsync.busses.file_input_bus import FileInputBus from cloudsync.utils.heartbeat import HeartBeatProvider VERSION = "0.2.4" arguments = sys.argv log_level = int(arguments[1]) logging.basicConfig(filename='cloudsync.log', level=log_level) app = Flask(__name__) api = Api(app=app, version=VERSION, title="CloudSync Registration API", description="Interface with DIA Manufacturing Tool") for handler in app.logger.handlers: app.logger.removeHandler(handler) handler = logging.FileHandler('cloudsync.log') handler.setLevel(log_level) default_formatter = logging.Formatter('[%(asctime)s] %(levelname)s in %(module)s: %(message)s') handler.setFormatter(default_formatter) app.logger.addHandler(handler) app.logger.setLevel(log_level) g_utils.add_logger(app.logger) g_config = helpers_read_config(CONFIG_PATH) reachability_provider = ReachabilityProvider(logger=app.logger) g_utils.add_reachability_provider(reachability_provider=reachability_provider) output_channel = FileOutputBus(logger=app.logger, max_size=1, file_channels_path=UI2CS_FILE_CHANNELS_PATH) network_request_handler = NetworkRequestHandler(logger=app.logger, max_size=1, output_channel=output_channel, reachability_provider=reachability_provider) message_handler = UICSMessageHandler(logger=app.logger, max_size=20, network_request_handler=network_request_handler, output_channel=output_channel, reachability_provider=reachability_provider) ui_cs_bus = FileInputBus(logger=app.logger, file_channels_path=UI2CS_FILE_CHANNELS_PATH, input_channel_name="inp.buf", g_config=g_config, message_handler=message_handler) heartbeat_provider = HeartBeatProvider(logger=app.logger, network_request_handler=network_request_handler, output_channel=output_channel) if g_config[CONFIG_DEVICE][CONFIG_DEVICE_MODE] == 'operation': heartbeat_provider.send_heartbeat = True else: heartbeat_provider.send_heartbeat = False parser = reqparse.RequestParser() # START - REGISTRATION ENDPOINTS @api.route("/version") class Version(Resource): @api.response(OK, "Success") def get(self): app.logger.info("Received /version HTTP request") return { "version": VERSION }, OK @api.route("/credentials") class Credentials(Resource): FIELD_CREDENTIALS = api.model("Credentials", { "certificate": fields.String, "public_key": fields.String, "private_key": fields.String, }) @api.doc(body=FIELD_CREDENTIALS, validate=True) @api.response(OK, "Success") @api.response(BAD_REQUEST, "Validation Error") def put(self): """ 4. Update the device's certificate and keys Manufacturing Tool -> Device """ app.logger.info("Received /credentials HTTP request") payload = request.json certificate = payload.get("certificate", None) private_key = payload.get("private_key", None) public_key = payload.get("public_key", None) invalid_params = [] if certificate is None: invalid_params.append("certificate") if private_key is None: invalid_params.append("private_key") if public_key is None: invalid_params.append("public_key") if len(invalid_params) > 0: return {"invalidAttributes": invalid_params}, BAD_REQUEST r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_SET_CREDENTIALS, url=request.url, payload=payload, method=request.method, g_config=g_config, ) network_request_handler.enqueue_request(r) return { "invalidAttributes": [], }, OK @api.route("/validate") class Validate(Resource): @api.response(OK, "Success") def head(self): """ 5. Initiate device connectivity test Manufacturing Tool -> Device """ app.logger.info("Received /validate HTTP request") r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_INIT_CONNECTIVITY_TEST, url=request.url, payload={}, method=request.method, g_config=g_config, ) network_request_handler.enqueue_request(r) # no body is returned return {}, OK @api.route("/reset") class Reset(Resource): @api.response(OK, "Success") def head(self): """ 13. Initiate a factory reset Assumes the connectivity test has already been completed Manufacturing Tool -> Device """ app.logger.info("Received /reset HTTP request") r = NetworkRequest(request_type=NetworkRequestType.MFT2CS_REQ_FACTORY_RESET, url=request.url, payload={}, method=request.method, g_config=g_config, ) network_request_handler.enqueue_request(r) heartbeat_provider.send_heartbeat = True return {}, OK # END - REGISTRATION ENDPOINTS @api.route("/config") class Config(Resource): @api.response(OK, "Success") def get(self): """ Get the current json config """ app.logger.info("Received /config HTTP request") return g_config, OK @api.route("/token") class Config(Resource): @api.response(OK, "Success") def get(self): """ Get the currently stored token """ app.logger.info("Received /token HTTP request") return helpers_read_access_token(DEVICE_KEBORMED_ACCESS_TOKEN_PATH), OK @api.route("/logs") class Logs(Resource): @api.hide def get(self): app.logger.info("Received /logs HTTP request") content = "" with open(CS_LOG_FILE, 'r') as f: content = f.read() return Response(content, mimetype="text/plain") def main(): if DEBUG: app.run(debug=False, use_reloader=False, host="0.0.0.0", port=g_config[CONFIG_DEVICE][CONFIG_DEVICE_PORT]) elif VM: app.logger.error("VM mode not implemented yet.") elif SERVER: app.logger.error("Server mode not implemented yet.") else: app.logger.error("Production mode not implemented yet.") if __name__ == '__main__': main()