def save_random_hex_str(dest_filedir, hex_str): """ Create file for random hex string and update node_info.csv :param dest_filedir: Destination File Directory :type dest_filedir: str :param hex_str: Random hex string to write :type hex_str: str :raises Exception: If there is any issue when writing to file :return: None on Success :rtype: None """ try: log.debug("Writing random hex string at location: " + dest_filedir + 'random.info') with open(dest_filedir + 'random.info', 'w+') as info_file: info_file.write(hex_str) with open(dest_filedir + 'node_info.csv', 'a') as info_file: info_file.write('random,file,hex2bin,' + dest_filedir + 'random.info') info_file.write('\n') except Exception as err: log.error(err)
def start_claim_process(mac_addr, node_platform, private_key): log.info("Creating session") curr_session = session.Session() header = curr_session.request_header try: # Set claim initiate data claim_init_data = set_claim_initiate_data(mac_addr, node_platform) # Perform claim initiate request claim_init_resp = claim_initiate(claim_init_data, header) # Set claim verify data claim_verify_data, node_info = set_claim_verify_data( claim_init_resp, private_key) # Perform claim verify request claim_verify_resp = claim_verify(claim_verify_data, header) # Get certificate from claim verify response node_cert = json.loads(claim_verify_resp.text)['certificate'] print("Claim certificate received") log.info("Claim certificate received") return node_info, node_cert except requests.exceptions.SSLError: raise SSLError except requests.ConnectionError: log.error("Please check the Internet connection.") exit(0)
def check_status(node_object, request_id): status = None while True: log.debug('Checking user-node association status.') try: status = node_object.get_mapping_status(request_id) except Exception as mapping_status_err: log.error(mapping_status_err) return else: log.debug('User-node association status ' + status) if status == 'requested': print('Checking User Node association status - Requested\n' 'Retrying...') elif status == 'confirmed': print('Checking User Node association status - Confirmed') return elif status == 'timedout': print('Checking User Node association status - Timeout') return elif status == 'discarded': print('Checking User Node association status - Discarded') return time.sleep(5) return
def claim_node(vars=None): """ Claim the node connected to the given serial port (Get cloud credentials) :param vars: `port` as key - Serial Port, defaults to `None` :type vars: str | None :raises Exception: If there is an HTTP issue while claiming :return: None on Success :rtype: None """ try: if not vars['port'] and not vars['mac'] and not vars['addr'] and not vars['platform']: sys.exit(vars['parser'].print_help()) if vars['addr'] and not vars['port'] and not vars['platform']: sys.exit('Invalid. <port> or --platform argument is needed.') if vars['port']: if not vars['mac'] and not vars['platform']: claim(port=vars['port'], node_platform=vars['platform'], mac_addr=vars['mac'], flash_address=vars['addr']) return if (vars['mac'] and not vars['platform']): sys.exit("Invalid. --platform argument needed.") if (not vars['mac'] and vars['platform']): sys.exit("Invalid. --mac argument needed.") if vars['mac']: if not re.match(r'([0-9A-F]:?){12}', vars['mac']): sys.exit('Invalid MAC address.') claim(port=vars['port'], node_platform=vars['platform'], mac_addr=vars['mac'], flash_address=vars['addr']) except Exception as claim_err: log.error(claim_err) return
def get_password(): """ Get Password as input and perform basic password validation checks. :raises SystemExit: If there is an issue in getting password :return: Password for User on Success :rtype: str """ log.info('Doing basic password confirmation checks.') password_policy = '8 characters, 1 digit, 1 uppercase and 1 lowercase.' password_change_attempt = 0 print('Choose a password') while password_change_attempt < MAX_PASSWORD_CHANGE_ATTEMPTS: log.debug('Password change attempt number ' + str(password_change_attempt + 1)) password = getpass.getpass('Password : '******'Password should contain at least', password_policy) password_change_attempt += 1 continue confirm_password = getpass.getpass('Confirm Password : '******'Passwords do not match!\n' 'Please enter the password again ..') password_change_attempt += 1 log.error('Maximum attempts to change password over. Please try again.') sys.exit(1)
def claim_initiate(claim_init_data, header): print("Claim initiate started") claim_initiate_url = CLAIM_INITIATE_URL try: # Claim Initiate Request log.info("Claim initiate started. Sending claim/initiate POST request") log.debug("Claim Initiate POST Request: url: " + claim_initiate_url + "data: " + str(claim_init_data) + "headers: " + str(header) + "verify: " + CERT_FILE) claim_initiate_response = requests.post(url=claim_initiate_url, data=claim_init_data, headers=header, verify=CERT_FILE) if claim_initiate_response.status_code != 200: log.error("Claim initiate failed.\n" + claim_initiate_response.text) exit(0) print("Claim initiate done") log.debug("Claim Initiate POST Response: status code: " + str(claim_initiate_response.status_code) + " and response text: " + claim_initiate_response.text) log.info("Claim initiate done") return claim_initiate_response except requests.exceptions.SSLError: raise SSLError except requests.ConnectionError: log.error("Please check the Internet connection.") exit(0)
def do_GET(self): """ Handle a GET request and writes the ESP Rainmaker Welcome HTML page(response) back to HTTP Client :raises Exception: If there is any File Handling Issue :return: None on Success and Failure :rtype: None """ log.debug('Loading the welcome page after successful login.') self.send_response(http_client.OK) self.send_header('Content-type', 'text/html') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() parts = urllib.parse.urlparse(self.path) query = _helpers.parse_unique_urlencoded(parts.query) self.server.query_params = query index_file = os.path.join(os.path.expanduser('.'), 'html/welcome.html') try: with open(index_file, 'rb') as home_page: self.wfile.write(home_page.read()) except Exception as file_err: log.error(file_err) sys.exit(1)
def remove_node(vars=None): """ Removes the user node mapping. :param vars: `nodeid` as key - Node ID for the node, defaults to `None` :type vars: dict | None :raises NetworkError: If there is a network connection issue during HTTP request for removing node :raises Exception: If there is an HTTP issue while removing node or JSON format issue in HTTP response :return: None on Success :rtype: None """ log.info('Removing user node mapping for node ' + vars['nodeid']) try: n = node.Node(vars['nodeid'], session.Session()) params = n.remove_user_node_mapping() except Exception as remove_node_err: log.error(remove_node_err) else: log.debug('Removed the user node mapping successfully.') print('Removed node ' + vars['nodeid'] + ' successfully.') return
def claim_verify(claim_verify_data, header): claim_verify_url = CLAIM_VERIFY_URL user_whitelist_err_msg = ('User is not allowed to claim esp32 device.' ' please contact administrator') claim_verify_enc_data = str(claim_verify_data).replace("'", '"') log.debug("Claim Verify POST Request: url: " + claim_verify_url + "data: " + str(claim_verify_enc_data) + "headers: " + str(header) + "verify: " + CERT_FILE) claim_verify_response = requests.post(url=claim_verify_url, data=claim_verify_enc_data, headers=header, verify=CERT_FILE) if claim_verify_response.status_code != 200: claim_verify_response_json = json.loads( claim_verify_response.text.lower()) if (claim_verify_response_json["description"] in user_whitelist_err_msg): log.error('Claim verification failed.\n' + claim_verify_response.text) print('\nYour account isn\'t whitelisted for ESP32.' ' Please send your registered email address to' ' [email protected] for whitelisting') else: log.error('Claim verification failed.\n' + claim_verify_response.text) exit(0) print("Claim verify done") log.debug("Claim Verify POST Response: status code: " + str(claim_verify_response.status_code) + " and response text: " + claim_verify_response.text) log.info("Claim verify done") return claim_verify_response
def flash_nvs_partition_bin(port, bin_to_flash, address): """ Flash binary onto node :param port: Serial Port :type port: str :param bin_to_flash: Filname of binary to flash :type bin_to_flash: str :raises Exception: If there is any issue when flashing binary onto node :return: None on Success :rtype: None """ try: if not port: sys.exit( "If you want to write the claim data to flash, please provide the <port> argument." ) print("Flashing binary onto node") log.info("Flashing binary onto node") command = ['--port', port, 'write_flash', address, bin_to_flash] esptool.main(command) except Exception as err: log.error(err) sys.exit(1)
def set_params(vars=None): """ Set parameters of the node. :param vars: `nodeid` as key - Node ID for the node,\n `data` as key - JSON data containing parameters to be set `or`\n `filepath` as key - Path of the JSON file containing parameters to be set,\n defaults to `None` :type vars: dict | None :raises Exception: If there is an HTTP issue while setting params or JSON format issue in HTTP response :return: None on Success :rtype: None """ log.info('Setting params of the node with nodeid : ' + vars['nodeid']) data = vars['data'] filepath = vars['filepath'] if data is not None: log.debug('Setting node parameters using JSON data.') # Trimming white spaces except the ones between two strings data = re.sub( r"(?<![a-z]|[A-Z])\s(?![a-z]|[A-Z])|\ (?<=[a-z]|[A-Z])\s(?![a-z]|[A-Z])|\ (?<![a-z]|[A-Z])\s(?=[a-z]|[A-Z])", "", data) try: log.debug('JSON data : ' + data) data = json.loads(data) except Exception: raise InvalidJSONError return elif filepath is not None: log.debug('Setting node parameters using JSON file.') file = Path(filepath) if not file.exists(): log.error('File %s does not exist!' % file.name) return with open(file) as fh: try: data = json.load(fh) log.debug('JSON filename :' + file.name) except Exception: raise InvalidJSONError return try: n = node.Node(vars['nodeid'], session.Session()) status = n.set_node_params(data) except Exception as set_params_err: log.error(set_params_err) else: print('Node state updated successfully.') return
def remove_shared_nodes(vars=None): """ Remove shared nodes :param vars: `nodes` as key - Node Id for the node :type vars: dict :param vars: `email` as key - Email address of the user :type vars: dict :raises Exception: If there is an issue while removing shared nodes :return: None on Success :rtype: None """ try: log.debug("Removing shared nodes") # Remove any spaces if exist node_ids = vars['nodes'].strip() # Check user input format ret_status = _check_user_input(node_ids) # Get email-id email_id = vars['email'] log.debug("Email-id set to: {}".format(email_id)) # Create API data dictionary api_data = {} api_data['nodes'] = node_ids api_data['email'] = email_id n = node.Node(None, session.Session()) log.debug("API data set to: {}".format(api_data)) # API call to remove the shared nodes node_json_resp = n.remove_shared_nodes(api_data) log.debug("Remove shared nodes response: {}".format(node_json_resp)) except Exception as get_node_status_err: log.error(get_node_status_err) else: try: log.debug("Displaying status") # Display result if not isinstance(node_json_resp, dict): print(node_json_resp) else: _display_status(node_json_resp) except AttributeError as err: log.debug("Error: {}".format(err)) _display_json(node_json_resp) log.debug("Removing shared nodes successful") return
def _load_source(name, path): try: from importlib.machinery import SourceFileLoader return SourceFileLoader(name, path).load_module() except ImportError: # importlib.machinery doesn't exists in Python 2 so we will use imp (deprecated in Python 3) import imp return imp.load_source(name, path) except Exception as load_source_err: log.error(load_source_err) sys.exit(1)
def logout(vars=None): """ Logout of the current session. :raises Exception: If there is any issue in logout for user :return: None on Success and Failure :rtype: None """ log.info('Logging out current logged-in user') # Removing the creds stored locally log.debug("Removing creds stored locally, invalidating token") config = configmanager.Config() # Get email-id of current logged-in user email_id = config.get_token_attribute('email') log.info('Logging out user: {}'.format(email_id)) # Ask user for ending current session # Get user input input_resp = config.get_input_to_end_session(email_id) if not input_resp: return # Call Logout API try: curr_session = session.Session() status_resp = curr_session.logout() log.debug("Logout API successful") except Exception as logout_err: log.error(logout_err) return # Check API status in response if 'status' in status_resp and status_resp['status'] == 'failure': print("Logout from ESP RainMaker Failed. Exiting.") print("[{}]:{}".format(status_resp['error_code'], status_resp['description'])) return # Remove current login creds ret_val = config.remove_curr_login_creds() if ret_val is None: print("Logout from ESP RainMaker Failed. Exiting.") return # Logout is successful print("Logged out from ESP RainMaker") log.debug('Logout Successful') log.debug("Local creds removed successfully") return
def login(vars=None): """ First time login of the user. :param vars: `email` as key - Email address of the user, defaults to `None` :type vars: dict :raises Exception: If there is any issue in login for user :return: None on Success and Failure :rtype: None """ log.info('Signing in the user. Username ' + str(vars['email'])) config = configmanager.Config() # Set email-id email_id = vars['email'] log.info('Logging in user: {}'.format(email_id)) # Check user current creds exist resp_filename = config.check_user_creds_exists() # If current creds exist, ask user for ending current session if resp_filename: # Get email-id of current logged-in user curr_email_id = config.get_token_attribute('email') log.info('Logging out user: {}'.format(curr_email_id)) # Get user input input_resp = config.get_input_to_end_session(curr_email_id) if not input_resp: return # Remove current login creds ret_val = config.remove_curr_login_creds(curr_creds_file=resp_filename) if ret_val is None: print("Failed to end previous login session. Exiting.") return else: log.debug("Current login creds not found at path: {}".format(resp_filename)) if vars['email'] is None: browser_login() return try: u = user.User(vars['email']) u.login() print('Login Successful') except Exception as login_err: log.error(login_err)
def claim_node(vars=None): """ Claim the node connected to the given serial port (Get cloud credentials) :param vars: `port` as key - Serial Port, defaults to `None` :type vars: str | None :raises Exception: If there is an HTTP issue while claiming :return: None on Success :rtype: None """ try: claim(vars['port']) except Exception as claim_err: log.error(claim_err) return
def get_node_status(vars=None): """ Shows the online/offline status of the node. :param vars: `nodeid` as key - Node ID for the node, defaults to `None` :type vars: dict | None :raises Exception: If there is an HTTP issue while getting node status :return: None on Success :rtype: None """ try: n = node.Node(vars['nodeid'], session.Session()) node_status = n.get_node_status() except Exception as get_node_status_err: log.error(get_node_status_err) else: print(json.dumps(node_status, indent=4)) return
def get_user_details(vars=None): """ Get details of current logged-in user """ try: # Get user details log.debug('Getting details of current logged-in user') curr_session = session.Session() user_info = curr_session.get_user_details() log.debug("User details received") except Exception as err: log.error(err) else: # Print API response output for key, val in user_info.items(): if key == "user_name": key = key + " (email)" title = key.replace("_", " ").title() print("{}: {}".format(title, val)) return
def get_params(vars=None): """ Get parameters of the node. :param vars: `nodeid` as key - Node ID for the node, defaults to `None` :type vars: dict | None :raises Exception: If there is an HTTP issue while getting params or JSON format issue in HTTP response :return: None on Success :rtype: None """ try: n = node.Node(vars['nodeid'], session.Session()) params = n.get_node_params() except SSLError: log.error(SSLError()) except NetworkError as conn_err: print(conn_err) log.warn(conn_err) except Exception as get_params_err: log.error(get_params_err) else: if params is None: log.error('Node status not updated.') return else: print(json.dumps(params, indent=4)) return params
def signup(vars=None): """ User signup to the ESP Rainmaker. :param vars: `email` as key - Email address of the user, defaults to `None` :type vars: dict :raises Exception: If there is any issue in signup for user :return: None on Success :rtype: None """ log.info('Signing up the user ' + vars['email']) u = user.User(vars['email']) password = get_password() try: status = u.signup_request(password) except Exception as signup_err: log.error(signup_err) else: if status is True: verification_code = input('Enter verification code sent on your' 'Email.\n Verification Code : ') try: status = u.signup(verification_code) except Exception as signup_err: log.error(signup_err) return print('Signup Successful\n' 'Please login to continue with ESP Rainmaker CLI') else: log.error('Signup failed. Please try again.') return
def set_config(self, data, config_file=CONFIG_FILE): """ Set the configuration file. :params data: Config Data to write to file :type data: dict :params config_file: Config filename to write config data to :type data: str :raises OSError: If there is an OS issue while creating new directory for config file :raises Exception: If there is a File Handling error while saving config to file :return: None on Success and Failure :rtype: None """ log.info("Configuring config file.") file_dir = Path(path.expanduser(HOME_DIRECTORY + CONFIG_DIRECTORY)) file = Path(path.expanduser(HOME_DIRECTORY) + config_file) if not file.exists(): try: if not file_dir.exists(): log.debug('Config directory does not exist,' 'creating new directory.') os.makedirs( path.expanduser(HOME_DIRECTORY) + CONFIG_DIRECTORY) except OSError as set_config_err: log.error(set_config_err) if set_config_err.errno != errno.EEXIST: raise set_config_err try: with open(path.join(path.expanduser(HOME_DIRECTORY), config_file), 'w') as config_file: json.dump(data, config_file) except Exception as set_config_err: raise set_config_err log.info("Configured config file successfully.")
def get_tokens(code): """ Get access token and set the config file after successful browser login. :raises Exception: If there is an HTTP issue in getting access token :raises SystemExit: If Exception is raised :return: None on Success and Failure :rtype: None """ log.info('Getting access tokens using authorization code.') client_id = serverconfig.CLIENT_ID request_data = 'grant_type=authorization_code&client_id=' + client_id +\ '&code=' + code + '&redirect_uri=' +\ serverconfig.REDIRECT_URL request_header = {'content-type': 'application/x-www-form-urlencoded'} try: response = requests.post(url=serverconfig.TOKEN_URL, data=request_data, headers=request_header, verify=configmanager.CERT_FILE) response.raise_for_status() except requests.exceptions.SSLError: raise SSLError except requests.exceptions.ConnectionError: raise NetworkError except Exception as get_token_err: log.error(get_token_err) sys.exit(1) else: config_data = {} result = response.json() config_data['idtoken'] = result['id_token'] config_data['refreshtoken'] = result['refresh_token'] config_data['accesstoken'] = result['access_token'] log.debug('Received access tokens using authorization code.') configmanager.Config().set_config(config_data) return
def list_shared_nodes(vars=None): """ List shared nodes :param vars: `node` as key - Node Id for the node (if provided) :type vars: dict :raises Exception: If there is an issue while getting shared nodes :return: None on Success :rtype: None """ try: log.debug("Get shared nodes") n = node.Node(vars['node'], session.Session()) log.debug("Node id received from user: {}".format(vars['node'])) # API node_json_resp = n.get_shared_nodes() log.debug("Get shared nodes response: {}".format(node_json_resp)) except Exception as get_node_status_err: log.error(get_node_status_err) else: try: # Display result log.debug("Displaying status") _display_status(node_json_resp) except AttributeError as err: log.debug("Error: {}".format(err)) _display_json(node_json_resp) log.debug("Get shared nodes successful") return
def login(vars=None): """ First time login of the user. :param vars: `email` as key - Email address of the user, defaults to `None` :type vars: dict :raises Exception: If there is any issue in login for user :return: None on Success :rtype: None """ log.info('Signing in the user. Username ' + str(vars['email'])) if vars['email'] is None: browser_login() return u = user.User(vars['email']) try: u.login() except Exception as login_err: log.error(login_err) else: print('Login Successful')
def get_nodes(vars=None): """ List all nodes associated with the user. :param vars: No Parameters passed, defaults to `None` :type vars: dict | None :raises Exception: If there is an HTTP issue while getting nodes :return: None on Success :rtype: None """ try: s = session.Session() nodes = s.get_nodes() except Exception as get_nodes_err: log.error(get_nodes_err) else: if len(nodes.keys()) == 0: print('User is not associated with any nodes.') return for key in nodes.keys(): print(nodes[key].get_nodeid()) return
def flash_bin_onto_node(port, esptool, bin_to_flash): """ Flash binary onto node :param port: Serial Port :type port: str :param esptool: esptool module :type esptool: module :param bin_to_flash: Filname of binary to flash :type bin_to_flash: str :raises Exception: If there is any issue when flashing binary onto node :return: None on Success :rtype: None """ try: command = ['--port', port, 'write_flash', '0x340000', bin_to_flash] esptool.main(command) except Exception as err: log.error(err) sys.exit(1)
def get_mqtt_host(vars=None): """ Returns MQTT Host endpoint :param vars: No Parameters passed, defaults to `None` :type vars: dict | None :raises NetworkError: If there is a network connection issue while getting MQTT Host endpoint :raises Exception: If there is an HTTP issue while getting MQTT Host endpoint or JSON format issue in HTTP response :return: MQTT Host endpoint :rtype: str """ log.info("Getting MQTT Host endpoint.") path = 'mqtt_host' request_url = serverconfig.HOST.split(serverconfig.VERSION)[0] + path try: log.debug("Get MQTT Host request url : " + request_url) response = requests.get(url=request_url, verify=configmanager.CERT_FILE) log.debug("Get MQTT Host resonse : " + response.text) response.raise_for_status() except requests.exceptions.SSLError: raise SSLError except requests.ConnectionError: raise NetworkError return except Exception as mqtt_host_err: log.error(mqtt_host_err) return try: response = json.loads(response.text) except Exception as json_decode_err: log.error(json_decode_err) if 'mqtt_host' in response: log.info("Received MQTT Host endpoint successfully.") print(response['mqtt_host']) else: log.error("MQTT Host does not exists.") return response['mqtt_host']
def forgot_password(vars=None): """ Forgot password request to reset the password. :param vars: `email` as key - Email address of the user, defaults to `None` :type vars: dict :raises Exception: If there is an HTTP issue while changing password for user :return: None on Success and Failure :rtype: None """ log.info('Changing user password. Username ' + vars['email']) u = user.User(vars['email']) status = False try: status = u.forgot_password() except Exception as forgot_pwd_err: log.error(forgot_pwd_err) else: verification_code = input('Enter verification code sent on your Email.' '\n Verification Code : ') password = get_password() if status is True: try: log.debug('Received verification code on email ' + vars['email']) status = u.forgot_password(password, verification_code) except Exception as forgot_pwd_err: log.error(forgot_pwd_err) else: print('Password changed successfully.' 'Please login with the new password.') else: log.error('Failed to reset password. Please try again.') return
def ota_upgrade(vars=None): """ Upload OTA Firmware Image and Set image url returned in response as node params """ try: node_id = vars['nodeid'] img_file_path = vars['otaimagepath'] if os.path.isabs(img_file_path) is False: img_file_path = os.path.join(os.getcwd(), img_file_path) img_name = img_file_path.split('/')[-1].split('.bin')[0] with open(img_file_path, 'rb') as f: fw_img_bytes = f.read() base64_fw_img = base64.b64encode(fw_img_bytes).decode('ascii') retries = MAX_HTTP_CONNECTION_RETRIES node_object = None status = None response = None service_name = None service_obj = None service_config = None node_params = None param_url_to_set = None curr_session = None while retries > 0: try: # If session is expired then to initialise the new session # internet connection is required. if not curr_session: curr_session = session.Session() if not node_object: node_object = node.Node(node_id, curr_session) log.info("Creating service object...") if not service_obj: service_obj = service.Service() log.info("Checking service " + service.OTA_SERVICE_TYPE + " in node config...") print("Checking " + service.OTA_SERVICE_TYPE + " in node config...") if not service_config and not service_name: service_config, service_name = service_obj.verify_service_exists(node_object, service.OTA_SERVICE_TYPE) if not service_config: log.error(service.OTA_SERVICE_TYPE + " not found.") break log.info("Checking service " + service.OTA_SERVICE_TYPE + " in config...Success") log.debug("Service config received: " + str(service_config) + " Service name received: " + str(service_name)) print("Uploading OTA Firmware Image...This may take time...") log.info("Uploading OTA Firmware Image...This may take time...") if not status and not response: # Upload OTA Firwmare Image status, response = service_obj.upload_ota_image(node_object, img_name, base64_fw_img) if status: break except SSLError: log.error(SSLError()) break except (NetworkError, RequestTimeoutError) as conn_err: print(conn_err) log.warn(conn_err) except Exception as node_init_err: log.error(node_init_err) break time.sleep(5) retries -= 1 if retries: print("Retries left:", retries) log.info("Retries left: " + str(retries)) if node_object is None: log.error('Initialising new session...Failed\n') return if not status or not 'success' in status: print("\n") log.error("OTA Upgrade...Failed") log.debug('OTA Upgrade...Failed ' 'status: ' + str(status) + ' response: ' + str(response)) return log.info('Upload OTA Firmware Image Request...Success') log.debug("Upload OTA Firmware Image Request - Status: " + json.dumps(status) + " Response: " + json.dumps(response)) retries = MAX_HTTP_CONNECTION_RETRIES ota_start_status = None node_params = None service_read_params = None service_write_params = None ota_status = None while retries > 0: try: if 'image_url' in response: param_url_to_set = response["image_url"] if not service_read_params and not service_write_params: log.info("Getting service params from node config") service_read_params, service_write_params = service_obj.get_service_params(service_config) log.debug("Service params received with read properties: " + str(service_read_params) + " Service params received with write properties: " + str(service_write_params)) log.info("Getting node params...") if not node_params: node_params = node_object.get_node_params() log.debug("Node params received: " + json.dumps(node_params)) print("Setting the OTA URL parameter...") if not ota_start_status: ota_start_status = service_obj.start_ota(node_object, node_params, service_name, service_write_params, param_url_to_set) log.debug("OTA status received: " + str(ota_start_status)) if not ota_start_status: log.error("Failed to start OTA service...Exiting...") break print("Getting OTA Status...") if not ota_status: ota_status = service_obj.check_ota_status(node_object, service_name, service_read_params) break except SSLError: log.error(SSLError()) break except (NetworkError, RequestTimeoutError) as conn_err: print(conn_err) log.warn(conn_err) except Exception as node_init_err: log.error(node_init_err) break time.sleep(5) retries -= 1 if retries: print("Retries left:", retries) log.info("Retries left: " + str(retries)) if ota_status in [None, False]: log.error("OTA Upgrade...Failed") log.debug('OTA Upgrade...Failed ' 'ota_status: ' + str(ota_status)) except KeyError as key_err: log.error("Key Error: " + str(key_err)) except Exception as ota_err: log.error(ota_err) return
def browser_login(): """ Opens browser with login url using Httpd Server. :raises Exception: If there is an HTTP issue while logging in through browser :return: None on Success and Failure :rtype: None """ log.info('Logging in through browser') server_instance = None for attempt in range(10): try: port = get_free_port() server_instance = HttpdServer(('localhost', port), HttpdRequestHandler) # Added timeout to handle keyboard interrupts for browser login. server_instance.timeout = 0.5 break except socket.error as err: log.warn('Error %s. Port %s is not available.' 'Trying with next port.', err, port) if server_instance is None: log.error('Error: Could not launch local webserver.' 'Use --email option instead.') return url = serverconfig.LOGIN_URL + str(port) +\ '&host_url=' + serverconfig.HOST + 'login' +\ '&github_url=' + serverconfig.EXTERNAL_LOGIN_URL +\ str(port) print('Opening browser window for login...') open_status = webbrowser.open(url) if open_status is False: log.error('Failed to open login page. Please try again.') return else: print('Use the browser for login. Press ctrl+C to abort.') log.debug('Web browser opened. Waiting for user login.') try: while True: server_instance.handle_request() if 'error' in server_instance.query_params: log.error('Authentication Error: "%s". Description: "%s" ' + server_instance.query_params['error'] + server_instance.query_params.ge('error_description')) return if 'code' in server_instance.query_params: log.debug('Login successful. Received authorization code.') code = server_instance.query_params['code'] get_tokens(code) print('Login successful') return if 'id_token' in server_instance.query_params and \ 'refresh_token' in server_instance.query_params: log.debug('Login successful.' 'Received idtoken and refresh token.') config_data = {} config_data['idtoken'] = server_instance.query_params[ 'id_token' ] config_data['refreshtoken'] = server_instance.query_params[ 'refresh_token' ] config_data['accesstoken'] = server_instance.query_params[ 'access_token' ] configmanager.Config().set_config(config_data) print('Login successful') return except Exception as browser_login_err: log.error(browser_login_err)