def set_mandatory_update_status(): """API to save the mandatory update status to the software update status file. Returns: dict: Execution status if the API call was successful. """ webserver_node = webserver_publisher_node.get_webserver_node() update_completed_value = request.json.get("update_completed") if update_completed_value is None: return jsonify({ "success": False, "reason": "Status must be a boolean" }) webserver_node.get_logger().info( "Setting mandatory software update status to " f"{update_completed_value}") software_update_status = {"update_completed": update_completed_value} try: with open(SOFTWARE_UPDATE_STATUS_PATH, "w") as software_update_status_file: json.dump(software_update_status, software_update_status_file) return jsonify({"success": True}) except IOError: webserver_node.get_logger().error( "Unable to set software update status: " f"{software_update_status}") return jsonify({"success": False})
def get_battery_level(): """API to call the service to get the current vehicle battery level information. Returns: dict: Execution status if the API call was successful, vehicle battery level details and error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() try: battery_level_req = BatteryLevelSrv.Request() battery_level_res = call_service_sync(webserver_node.battery_level_cli, battery_level_req) if battery_level_res: data = {"battery_level": battery_level_res.level, "success": True} webserver_node.get_logger().info( f"Battery Level: {data['battery_level']}") return jsonify(data) else: return jsonify(success=False, reason="Error") except Exception as ex: webserver_node.get_logger().error( f"Unable to reach battery level server: {ex}") return jsonify(success=False, reason="Error")
def is_ssh_default_password_changed(): """API called to check if the default password for SSH is changed. This will populate the ssh enabled radio button in the UI. Returns: dict: Execution status if the API call was successful, flag to indicate if default ssh password is changed and with error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info("Providing ssh enabeld as response") try: # Authenticate against default password if pam.pam().authenticate(DEFAULT_USER, DEFAULT_SSH_PASSWORD): return jsonify(success=True, isDefaultSshPasswordChanged=False, reason="Default password not changed") else: return jsonify(success=True, isDefaultSshPasswordChanged=True, reason="Default password changed") except Exception as ex: webserver_node.get_logger().error( f"Failed check if the ssh password is default: {ex}") return jsonify(success=False, isDefaultSshPasswordChanged=False, reason="Error")
def get_sensor_status(): """Helper function to call the service to get the status of the sensor connected to the vehicle. Returns: tuple: A tuple with error code and SensorStatusCheckSrv.Response object. """ webserver_node = webserver_publisher_node.get_webserver_node() try: sensor_status_req = SensorStatusCheckSrv.Request() sensor_status_res = call_service_sync(webserver_node.sensor_status_cli, sensor_status_req) if sensor_status_res and sensor_status_res.error == 0: webserver_node.get_logger().info( "Verify required sensor status: " f"Camera status: {sensor_status_res.single_camera_status}, " f"Stereo status: {sensor_status_res.stereo_camera_status}, " f"Lidar status: {sensor_status_res.lidar_status}") return 0, sensor_status_res else: webserver_node.get_logger().error( "Failed to call the sensor status service") return 1, {} except Exception as ex: webserver_node.get_logger().error( f"Unable to reach sensor status server: {ex}") return 1, {}
def api_wifi_information(): """API to get the list of available WiFi networks. This will populate the wifi drop down in the UI. Returns: list: List of dict objects with WiFi network details. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info("Providing wifi information as response") ssid_set = set() cmd = "/usr/bin/nmcli -t -f ssid,signal,security -e no device wifi list" wifi_list = list() wifi_lines = utility.execute(cmd, shlex_split=True)[1].split("\n") for wifi in wifi_lines: words = wifi.split(":") if words[0] in ssid_set or words[0] == "--" or len(words[0]) == 0: continue ssid_set.add(words[0]) wifi_data = { "ssid": words[0], "strength": math.floor(1.0 + float(words[1]) / 30.0), "security_info": words[2] } wifi_list.append(wifi_data) return jsonify(wifi_list)
def read_model_metadata_file(model_metatdata_file): """Helper method that reads the model metadata file for the model selected and validates the sensor configuration. Args: model_metatdata_file (str): Path to the model_metadata file. Returns: tuple: A tuple of error code, error message and the JSON data with the content read from model_metadata.json of the model. """ webserver_node = webserver_publisher_node.get_webserver_node() try: if (not os.path.isfile(model_metatdata_file)): webserver_node.get_logger().error( f"No model_metadata_file: {model_metatdata_file}.") # return 1 which means model_metadata file is not found return 1, "No model_metadata_file for the model selected", {} with open(model_metatdata_file) as json_file: data = json.load(json_file) return 0, "", data except Exception as ex: webserver_node.get_logger().error( f"Error while reading model_metadata.json: {ex}") return 1, "Error while reading model_metadata.json", {}
def api_manual_drive(): """API that publishes control messages to control the angle and throttle in manual drive mode. Returns: dict: Execution status if the API call was successful. """ webserver_node = webserver_publisher_node.get_webserver_node() angle = request.json.get("angle") throttle = request.json.get("throttle") max_speed = request.json.get("max_speed") if angle is None: return api_fail("angle is required") if throttle is None: return api_fail("throttle is required") if max_speed is None: return api_fail("max_speed is required") if angle < -1.0 or angle > 1.0: return api_fail("angle out of range") if throttle < -1.0 or throttle > 1.0: return api_fail("throttle out of range") webserver_node.get_logger().info(f"Angle: {angle} Throttle: {throttle}") # Create the servo message. msg = ServoCtrlMsg() # bound the throttle value based on the categories defined msg.angle = -1.0 * get_categorized_manual_angle(angle) categorized_throttle = get_categorized_manual_throttle(throttle) msg.throttle = -1.0 * get_rescaled_manual_speed(categorized_throttle, max_speed) webserver_node.pub_manual_drive.publish(msg) return jsonify({"success": True})
def api_set_start_stop(): """API to call the enable_state service to start and stop the vehicle. Returns: dict: Execution status if the API call was successful and error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() start_stop = request.json.get("start_stop") if start_stop is None: return jsonify({"success": False, "reason": "start_stop must be set."}) webserver_node.get_logger().info( f"Changed the enable state to {start_stop}") start_stop_state = False if start_stop == "stop" else True try: enable_state_req = EnableStateSrv.Request() enable_state_req.is_active = start_stop_state enable_state_res = call_service_sync(webserver_node.enable_state_cli, enable_state_req) if enable_state_res and (enable_state_res.error == 0): return jsonify({"success": True}) else: return jsonify({"success": False, "reason": "Error"}) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach enable state server: {ex}") return jsonify({ "success": False, "reason": "Unable to reach enable state server." })
def is_usb_connected(): """API to return information if the DeepRacer vehicle is connected the micro-USB cable to laptop/computer. Returns: [type]: True if the vehicle is connected to USB """ webserver_node = webserver_publisher_node.get_webserver_node() is_usb_connected = False conn_res = check_usb_connection() usb_connected = True if conn_res["success"] and conn_res[ "is_usb_connected"] else False if request.headers["Referer"].find( "deepracer.aws") != -1 and usb_connected: is_usb_connected = True webserver_node.get_logger().info( f"host: {request.headers['Referer']} " f"otg_connected: {'connected' if usb_connected else 'not connected'} " f"is_usb_connected: {'connected' if is_usb_connected else 'not connected'}" ) return jsonify({ "success": True, "is_usb_connected": is_usb_connected, })
def is_ssh_enabled(): """API called to execute commands to check if SSH is enabled. This will populate the ssh enabled radio button in the UI. Returns: dict: Execution status if the API call was successful, flag to indicate if ssh is enabled and with error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info("Providing ssh enabled as response") try: # Check SSH status if utility.execute("/bin/systemctl --no-pager status ssh", shlex_split=True)[1].find("active (running)") > -1: # Check UFW status stdout = utility.execute("/usr/sbin/ufw status", shlex_split=True)[1] if re.search("22.*ALLOW", stdout): return jsonify(success=True, isSshEnabled=True, reason="Ssh is enabled.") else: return jsonify(success=True, isSshEnabled=False, reason="Ssh not enabled.") else: return jsonify(success=True, isSshEnabled=False, reason="Ssh not enabled.") except Exception as ex: webserver_node.get_logger().error( f"Failed check if ssh is enabled: {ex}") return jsonify(success=False, isSshEnabled=False, reason="Error")
def execute(cmd, input_str=None, shell=False, shlex_split=False): """Execute the commands on shell terminal. Args: cmd (str): Command to be executed. input_str (str, optional): Input string that has to be passed to the shell input. Defaults to None. shell (bool, optional): Specifies whether to use the shell as the program to execute. Defaults to False. shlex_split(bool, optional): Specifies whether to split the command. Defaults to False. Returns: tuple: A tuple of return code and the output of the command. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info(f"Command executing: {cmd}") if shlex_split: cmd = shlex.split(cmd) proc = Popen(cmd, stdout=PIPE, stdin=PIPE, stderr=STDOUT, universal_newlines=True, shell=shell) stdout = proc.communicate(input=input_str)[0] webserver_node.get_logger().info(f"{cmd} : execute output: {stdout}") return proc.returncode, stdout
def is_network_inactive(ssid): """Check if the supplied SSID is currently not connected, but previously connected. Args: ssid (str): SSID value. Returns: bool: True if the SSID is inactive else False. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info(f"Checking if ssid: {ssid} is inactive") is_present = False stdout = execute("/usr/bin/nmcli -t -f name -e no con show", shlex_split=True)[1] for line in stdout.splitlines(): if line == ssid: is_present = True break if is_present and not is_network_connected(ssid): return True return False
def begin_software_update(): """API to call the service to begin the software update process. Returns: dict: Execution status if the API call was successful and error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() try: webserver_node.get_logger().info("Started software update.") begin_sw_update_req = BeginSoftwareUpdateSrv.Request() begin_sw_update_req.sleep_time_before_reboot = SLEEP_TIME_BEFORE_REBOOT begin_sw_update_res = call_service_sync( webserver_node.begin_sw_update_cli, begin_sw_update_req) if begin_sw_update_res and begin_sw_update_res.response_status: return jsonify({"success": True}) else: webserver_node.get_logger().error( "Begin software update service call failed") return jsonify({ "success": False, "reason": "Update service call failed" }) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach begin update server: {ex}") return jsonify({ "success": False, "reason": "Unable to reach begin update server" })
def control_modes_available(): """API to call the GetCtrlModesCountSrv service to get the list of available modes in ctrl_pkg (autonomous/manual/calibration/followtheleader). Returns: dict: Execution status if the API call was successful, list of available modes and error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info("Providing the number of available modes") try: get_ctrl_modes_req = GetCtrlModesSrv.Request() get_ctrl_modes_res = call_service_sync( webserver_node.get_ctrl_modes_cli, get_ctrl_modes_req) control_modes_available = list() for mode in get_ctrl_modes_res.modes: control_modes_available.append(constants.MODE_DICT[mode]) data = { "control_modes_available": control_modes_available, "success": True } return jsonify(data) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach get ctrl modes service: {ex}") return jsonify(success=False, reason="Error")
def api_adjust_calibrating_wheels(cali_type): """API to call the service to publishes a message withPWM measurement to adjust wheels while calibrating. Args: cali_type (int): Calibration type identifying steering/throttle calibration. Returns: dict: Execution status if the API call was successful. """ webserver_node = webserver_publisher_node.get_webserver_node() form_data = request.json if cali_type == "angle": angle = float( int(form_data["pwm"]) * PWM_ANGLE_CONVERSION + PWM_OFFSET) throttle = -1.0 else: angle = -1.0 throttle = float( int(form_data["pwm"]) * PWM_THROTTLE_CONVERSION + PWM_OFFSET) webserver_node.get_logger().info(f"Angle: {angle} Throttle: {throttle}") msg = ServoCtrlMsg() msg.angle = angle msg.throttle = throttle webserver_node.pub_calibration_drive.publish(msg) return jsonify({"success": True})
def set_calibration_mode(): """API to call the service to activate calibration mode. Returns: dict: Execution status if the API call was successful. """ webserver_node = webserver_publisher_node.get_webserver_node() try: vehicle_state_req = ActiveStateSrv.Request() vehicle_state_req.state = CALIBRATION_MODE vehicle_state_res = call_service_sync(webserver_node.vehicle_state_cli, vehicle_state_req) enable_state_req = EnableStateSrv.Request() enable_state_req.is_active = True enable_state_res = call_service_sync(webserver_node.enable_state_cli, enable_state_req) success = (vehicle_state_res and vehicle_state_res.error == 0 and enable_state_res and enable_state_res.error == 0) if not success: webserver_node.get_logger().error( "Vehicle state service call failed") return jsonify(success=False, reason="Error") return jsonify(success=True) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach vehicle state server: {ex}") return jsonify(success=False, reason="Error")
def api_get_logs(log_type, num_lines): """API to return the logs of appropriate type and logging window based on user selection. Args: log_type (str): Log type attribute name pointing to the log file location. Defined in the constants file. num_lines (int): Number of latest log lines to return. Returns: dict: Execution status if the API call was successful and the log file read response. """ webserver_node = webserver_publisher_node.get_webserver_node() num_lines = 1000 if num_lines > 1000 else num_lines log_content = "" try: with VEHICLE_LOGS_BLUEPRINT.open_resource(getattr( constants, log_type)) as logfile: lines = logfile.readlines()[-num_lines:] for i in range(0, len(lines)): log_content = log_content + lines[i].decode("utf-8") except AttributeError: webserver_node.get_logger().error("Type of log does not exist!") log_content = "Type of log does not exist!" except IOError: webserver_node.get_logger().error("File Not Found!") log_content = "File Not Found!" return jsonify({"success": True, "data": log_content})
def get_device_info(): """API to call the service to get the current hardware version of the DeepRacer vehicle and the software version of aws-deepracer-core package. Returns: dict: Execution status if the API call was successful, hardware and software version details and error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info( "Providing hardware and software revision " "details as response") try: get_revision_info_req = GetDeviceInfoSrv.Request() get_revision_info_res = call_service_sync( webserver_node.get_revision_info_cli, get_revision_info_req) if get_revision_info_res and get_revision_info_res.error == 0: data = { "hardware_version": get_revision_info_res.hardware_version, "software_version": get_revision_info_res.software_version, "success": True } webserver_node.get_logger().info( f"Hardware version: {data['hardware_version']}, " f"Software version: {data['software_version']}") else: webserver_node.get_logger().error( "Get device info service call failed") data = {"reason": "Error", "success": False} return jsonify(data) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach revision info server: {ex}") return jsonify(success=False, reason="Error")
def update_password_api(): """API that updates the console password to the new one sent as a parameter. Returns: dict: Execution status if the API call was successful, flag to indicate if password update was successful and error reason if call fails. """ webserver_node = webserver_publisher_node.get_webserver_node() old_password = request.json.get("old_password").encode("utf-8") new_password = request.json.get("new_password").encode("utf-8") try: with open(PASSWORD_PATH, "r") as pwd_file: password_digest = pwd_file.readline() if hmac.compare_digest(compute_password_digest(old_password), password_digest): with open(PASSWORD_PATH, "w") as pwd_file: pwd_file.write(compute_password_digest(new_password)) pwd_file.close() return jsonify({"success": True}) else: return jsonify({"success": False, "reason": "The password is incorrect. Provide your current password."}) except IOError: webserver_node.get_logger().error("Password.txt not found in given path") return jsonify({"success": False, "reason": "Password.txt not found."})
def max_nav_throttle(): """API to call the navigation_throttle service to set the throttle scale in the autonomous mode. Returns: dict: Execution status if the API call was successful and error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() nav_throttle = request.json.get("throttle") if nav_throttle is None: return jsonify({"success": False, "reason": "value must be set."}) webserver_node.get_logger().info( f"Setting max navigation throttle to {nav_throttle}") try: set_throttle_req = NavThrottleSrv.Request() set_throttle_req.throttle = nav_throttle / constants.MAX_AUTO_THROTTLE_VAL set_throttle_res = call_service_sync(webserver_node.set_throttle_cli, set_throttle_req) if set_throttle_res and (set_throttle_res.error == 0): return jsonify({"success": True}) else: return jsonify( success=False, reason="Failed to call the navigation throttle service") except Exception as ex: webserver_node.get_logger().error( f"Unable to reach navigation throttle server: {ex}") return jsonify(success=False, reason="Unable to reach navigation throttle server")
def get_software_update_status(): """API to stream the software update progress percentage and the current state. Returns: flask.Response: Flask response object with the content_type set to text/event-stream. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info("Inside the update status function") def events(): webserver_node.get_logger().info( "Running software update event source") for i, c in enumerate(itertools.cycle("\|/-")): try: pct_dict = webserver_node.pct_dict_db.get_nowait() percentage_completion = pct_dict["update_pct"] result = f"status:{pct_dict['status']}|update_pct:{percentage_completion}" yield "data: %s %d\n\n" % (result, i) # The sleep is introduced here so as to fetch the next message from # the software_update_status service. This is rate at which the UI shows # the change in the status querying the service. So this will provide us # to control the rate at which we would like to see the software update # information on the browser. For now its set to 1 seconds. time.sleep(SOFTWARE_UPDATE_FETCH_FREQUENCY) except Exception as ex: webserver_node.get_logger().error( f"Unable to reach update status service: {ex}") result = "status:checking|update_pct:0" yield f"data: {result} {1}\n\n" break return Response(events(), content_type="text/event-stream")
def max_ftl_speed(): """API to call the SetMaxSpeedSrv service to set the throttle scale in the followtheleader mode. Returns: dict: Execution status if the API call was successful and error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() ftl_speed = request.json.get("throttle") if ftl_speed is None: return jsonify({"success": False, "reason": "value must be set."}) webserver_node.get_logger().info(f"Setting max ftl speed to {ftl_speed}%") try: set_speed_req = SetMaxSpeedSrv.Request() set_speed_req.max_speed_pct = float(ftl_speed / 100) set_speed_res = call_service_sync(webserver_node.set_ftl_max_speed_cli, set_speed_req) if set_speed_res and (set_speed_res.error == 0): return jsonify({"success": True}) else: return jsonify(success=False, reason="Failed to call the SetMaxSpeed service") except Exception as ex: webserver_node.get_logger().error( f"Unable to reach SetMaxSpeed server: {ex}") return jsonify(success=False, reason="Unable to reach SetMaxSpeed server")
def api_set_drive_mode(): """API to toggle the drive mode between Autonomous/Manual mode. Returns: dict: Execution status if the API call was successful and error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() drive_mode = request.json.get("drive_mode") if drive_mode is None: return jsonify({"success": False, "reason": "drive_mode must be set."}) webserver_node.get_logger().info(f"Changed the vehicle state to {drive_mode}") drive_mode_state = 0 if drive_mode == "manual" else 1 try: vehicle_state_req = ActiveStateSrv.Request() vehicle_state_req.state = drive_mode_state vehicle_state_res = call_service_sync(webserver_node.vehicle_state_cli, vehicle_state_req) if vehicle_state_res and (vehicle_state_res.error == 0): return jsonify(success=True) else: webserver_node.get_logger().error("Vehicle state service call failed") return jsonify(success=False, reason="Error") except Exception as ex: webserver_node.get_logger().error(f"Unable to reach vehicle state server: {ex}") return jsonify({"success": False, "reason": "Unable to reach vehicle state server."})
def model_file_upload(): """API to call the service to upload models to the artifacts directory. Returns: dict: Execution status if the API call was successful and the response message. """ webserver_node = webserver_publisher_node.get_webserver_node() # # Check if the file received is a tar.gz # file_obj = request.files["file"] file_name = file_obj.filename secured_file = secure_filename(file_name) if file_name.endswith(".tar.gz"): folder_name = file_name[:-7] else: return jsonify({ "success": False, "message": "Failed to upload the model. Not a .tar.gz file" }) # Always create a new directory. If the folder already exists. # Delete and Create a new one. dir_path = os.path.join(constants.MODEL_DIRECTORY_PATH, folder_name) if os.path.exists(dir_path): shutil.rmtree(dir_path) os.makedirs(dir_path) # Save the uploaded file in the artifacts directory. webserver_node.get_logger().info( "Uploaded model file: {}".format(file_name)) file_obj.save(os.path.join(dir_path, secured_file)) # Optimizing the model once the file is uploaded. # Converting the .tar.gz to optimized inference model. upload_model_req = ConsoleModelActionSrv.Request() upload_model_req.model_path = dir_path # action=1 (For upload the model) & action=0 for deleting the model upload_model_req.action = 1 upload_model_res = call_service_sync(webserver_node.model_action_cli, upload_model_req) if upload_model_res: webserver_node.get_logger().info( f"Uploaded model status return {upload_model_res.status}") if upload_model_res.status == "done-upload": return jsonify({ "success": True, "message": "Model uploaded successfully to your vehicle" }) return jsonify({ "success": False, "message": "Failed to upload & optimize the model" })
def load_lidar_configuration(sensors, data): """Helper method to load the LiDAR configuration data if present in the model_metadata.json file of the data. Args: sensors (list): List of SensorInputKeys enum objects which the model was trained on. data (dict): JSON data with the content read from model_metadata.json of the model. Returns: tuple: A tuple of error code, error message and the LiDAR configuration dictionary. """ webserver_node = webserver_publisher_node.get_webserver_node() try: # Set default values in case the "lidar configuration" is not # defined in model_metadata.json. model_lidar_config = constants.DEFAULT_LIDAR_CONFIG # Set default values for SECTOR_LIDAR if this sensor is used if constants.SensorInputKeys.SECTOR_LIDAR in sensors: model_lidar_config = constants.DEFAULT_SECTOR_LIDAR_CONFIG model_lidar_config[ constants.ModelMetadataKeys.USE_LIDAR] = sensors and ( constants.SensorInputKeys.LIDAR in sensors or constants.SensorInputKeys.SECTOR_LIDAR in sensors) # Load the lidar configuration if the model uses lidar and has custom # lidar configurations. if model_lidar_config[constants.ModelMetadataKeys.USE_LIDAR] \ and constants.ModelMetadataKeys.LIDAR_CONFIG in data: lidar_config = data[constants.ModelMetadataKeys.LIDAR_CONFIG] model_lidar_config[ constants.ModelMetadataKeys.NUM_LIDAR_VALUES] = lidar_config[ constants.ModelMetadataKeys.NUM_LIDAR_VALUES] model_lidar_config[ constants.ModelMetadataKeys.MIN_LIDAR_ANGLE] = lidar_config[ constants.ModelMetadataKeys.MIN_LIDAR_ANGLE] model_lidar_config[ constants.ModelMetadataKeys.MAX_LIDAR_ANGLE] = lidar_config[ constants.ModelMetadataKeys.MAX_LIDAR_ANGLE] model_lidar_config[ constants.ModelMetadataKeys.MIN_LIDAR_DIST] = lidar_config[ constants.ModelMetadataKeys.MIN_LIDAR_DIST] model_lidar_config[ constants.ModelMetadataKeys.MAX_LIDAR_DIST] = lidar_config[ constants.ModelMetadataKeys.MAX_LIDAR_DIST] model_lidar_config[ constants.ModelMetadataKeys. LIDAR_CLIPPING_DIST] = lidar_config[ constants.ModelMetadataKeys.LIDAR_CLIPPING_DIST] model_lidar_config[ constants.ModelMetadataKeys.NUM_LIDAR_SECTORS] = lidar_config[ constants.ModelMetadataKeys.NUM_LIDAR_SECTORS] return 0, "", model_lidar_config except Exception as ex: webserver_node.get_logger().error( "Unable to connect to vehicle with current " f"LiDAR configuration: {ex}") return 1, "Unable to connect to vehicle with current LiDAR configuration", {}
def call_service_sync(cli, req, timeout=10, sleep_time=0.01): """A wrapper function to call the services and wait for the results until timeout. Args: cli (rclpy.client.Client): Client object using which we call the service. req (Request): Service request object. timeout (int, optional): Time in seconds to keep checking for service call to return result before removing the request. Defaults to 60. sleep_time (float, optional): Time in seconds to sleep before each check for returned result from service call. Defaults to 0.01. Returns: Response: The service response. """ webserver_node = webserver_publisher_node.get_webserver_node() if cli.service_is_ready(): webserver_node.get_logger().info( f"Service call initiated: {cli.srv_name}") future = cli.call_async(req) sequence = -1 for seq, req_future in cli._pending_requests.items(): if req_future == future: sequence = seq break webserver_node.get_logger().info( f"New request: {sequence} {cli.srv_name}") elapsed_time = 0 while not future.done(): if elapsed_time == int(elapsed_time): webserver_node.get_logger().info( f"Service call not finished: {sequence} {cli.srv_name}") time.sleep(sleep_time) elapsed_time += sleep_time if elapsed_time >= timeout: webserver_node.get_logger().info( "Service call was not completed before timeout: " f"{sequence} {cli.srv_name} {timeout}") future.cancel() if future.cancelled(): webserver_node.get_logger().error( f"Service was cancelled: {sequence} {cli.srv_name}") return None webserver_node.get_logger().info( f"Service call finished: {sequence} {cli.srv_name}") if future.exception() is not None: webserver_node.get_logger().error( f"Error while calling service: {sequence} - " f"{cli.srv_name} - {future.exception()}") return future.result() else: webserver_node.get_logger().info( f"Service is not ready: {cli.srv_name}") return None
def ssh_reset(): """API called to execute commands to reset the ssh password with the new one. Returns: dict: Execution status if the API call was successful and with error reason if failed. """ webserver_node = webserver_publisher_node.get_webserver_node() webserver_node.get_logger().info( "User requesting for resetting the ssh credentials") try: old_ssh_password = request.json["oldPassword"] new_ssh_password = request.json["newPassword"] # Check if old password is correct if not pam.pam().authenticate(DEFAULT_USER, old_ssh_password): return jsonify(success=False, reason="The password is incorrect. " "Provide your current password.") # Check if the default password is updated passwd_status_cmd = f"/usr/bin/passwd --status {DEFAULT_USER}" passwd_status_output = utility.execute(passwd_status_cmd, shlex_split=True)[1] # Execute passwd command based on the status of the password obtained above if passwd_status_output.split()[1] == "P": webserver_node.get_logger().info("Usable Password present") if (utility.execute( f"/usr/bin/sudo -u {DEFAULT_USER} /usr/bin/passwd", input_str=(f"{old_ssh_password}" f"\n{new_ssh_password}" f"\n{new_ssh_password}"), shlex_split=True)[1].find("successfully")) == -1: return jsonify(success=False, reason="The password update was unsuccessful.") else: return jsonify(success=True) elif passwd_status_output.split()[1] == "NP": webserver_node.get_logger().info("No Password present") if (utility.execute( f"/usr/bin/passwd {DEFAULT_USER}", input_str=(f"{new_ssh_password}\n" f"{new_ssh_password}"), shlex_split=True)[1].find("successfully")) > -1: return jsonify(success=True) else: return jsonify(success=False, reason="Unable to change the SSH password") except Exception: return jsonify(success=False, reason="Error")
def is_model_loading(): """API to stream the model loading status. Returns: flask.Response: Flask response object with the content_type set to text/event-stream. """ webserver_node = webserver_publisher_node.get_webserver_node() is_model_loading_req = GetModelLoadingStatusSrv.Request() is_model_loading_res = call_service_sync( webserver_node.is_model_loading_cli, is_model_loading_req) model_loading_status = "error" if is_model_loading_res is not None and is_model_loading_res.error == 0: model_loading_status = is_model_loading_res.model_loading_status return jsonify({"success": True, "isModelLoading": model_loading_status})
def reset_default(): """Helper method to reset the password to the default password found on vehicle. """ webserver_node = webserver_publisher_node.get_webserver_node() if os.path.exists(DEFAULT_PASSWORD_PATH): webserver_node.get_logger().info("Default password file found") with open(DEFAULT_PASSWORD_PATH, "r") as pwd_file: default_pass = pwd_file.readline().strip() else: default_pass = "******" webserver_node.get_logger().info("Default password file not found") with open(DESTINATION_PATH, "w") as pwd_file: pwd_file.write(compute_password_digest(default_pass)) webserver_node.get_logger().info("Password reset to default")
def home_page(): """API to load home page when if authenticated else redirect to login page. Returns: flask.Response: Response object with login page or home page details. """ webserver_node = webserver_publisher_node.get_webserver_node() status, _ = check_authentication() if status: webserver_node.get_logger().info("Authenticated") return render_template("index.html") else: resp = make_response(render_template("login.html"), 200) return resp