def _print_status(cnt, step_cnt, msg=None): if cnt % step_cnt == 0: curr_time = time.time() timestamp = datetime.datetime.fromtimestamp(curr_time).strftime( '%H:%M:%S') log.info('\n[{:<6}][Current Status] {}: {}'.format( msg, timestamp, str(cnt)))
def save_config(self, data): ''' Save login config data to file :param data: Login data to be set :type data: dict ''' try: log.debug("Saving login config data") if not os.path.isdir(CONFIG_DIRECTORY): log.info('Config directory does not exist, ' 'creating new directory : {}'.format( CONFIG_DIRECTORY)) os.makedirs(CONFIG_DIRECTORY) login_cfg_data = self._set_login_config_data(data) if not login_cfg_data: return False, False with open(self.config_file, 'w+', encoding='utf-8') as cfg_file: cfg_file.write(str(json.dumps(login_cfg_data))) return True, self.config_file except Exception as save_config_err: log.error(save_config_err) return False, False
def remove_curr_login_config(self, email=""): ''' Remove current login config from file :param email: Email-id of current user :type email: str ''' log.debug("Removing current login config data from file: {}".format( self.config_file)) while True: user_input = input('\nThis will end your current session for {}. ' 'Do you want to continue (Y/N)? :'.format( email)) if user_input not in ["Y", "y", "N", "n"]: log.info("Please provide Y/N only") continue elif user_input in ["N", "n"]: return False else: break try: os.remove(self.config_file) log.debug("Current login config removed from file: {}".format( self.config_file)) return True except Exception as e: log.debug('Error: {}. Failed to remove current login config ' 'from path {}'.format( e, self.config_file)) raise Exception('Error: Failed to remove current login ' 'config from path {}'.format(self.config_file))
def generate_cacert(cacert_info, ca_private_key): ''' Generate CA Certificate :param cacert_info: CA certificate info :type cacert_info: dict :param ca_private_key: CA Private Key :type ca_private_key: RSA Private Key ''' try: log.info("\nGenerating CA Certificate") ca_public_key = ca_private_key.public_key() subj_name_list = _create_subj_name_list(cacert_info) if not subj_name_list: return False issuer_name = [ x509.NameAttribute(NameOID.COMMON_NAME, cacert_info['common_name']) ] ca_cert = _generate_cert(subject_name=subj_name_list, issuer_name=issuer_name, public_key=ca_public_key, ca_key=ca_private_key, ca=True) if not ca_cert: return False return ca_cert except Exception as err: log.debug("Error: {} . Cannot create CA Certificate".format(err))
def download_from_url(request_url): ''' Download file from url :param request_url: Request URL to download file from :type request_url: str ''' try: response = None while True: try: log.debug("Downloading file from url: {}".format(request_url)) response = requests.get(url=request_url) response.raise_for_status() except requests.exceptions.SSLError: raise(SSLError()) except (ConnectionError): log.error(NetworkError()) except RequestException as err: log.error(err) if response: log.info("Node ids file downloaded successfully") log.debug("Response content: {}".format(response.content)) return response.content else: log.info("Retrying...") time.sleep(5) except Exception as err: raise Exception(err)
def configure_server(vars=None): ''' Set Server Config :param vars: `endpoint` as key - Endpoint of server to use :type vars: str :raises Exception: If there is any exception while configuring server KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Configure server") ret_status = _cli_arg_check(vars['endpoint'], '--endpoint <endpoint>') if not ret_status: return config = configmanager.Config(config="server") ret_status = config.set_server_config(vars['endpoint']) if not ret_status: log.error("Failed to save server config") return else: log.info("Saved new server config") log.info('You can now run: \npython rainmaker_admin_cli.py account ' 'login -h (Login)') except KeyboardInterrupt: log.error("\nServer config not set") except Exception as e: log.error("Error: {}".format(e))
def get_mqtthostname(self): ''' Get MQTT Hostname ''' try: backslash = '/' log.info("Sending request to get mqtt endpoint") retry_cnt = MAX_HTTP_CONNECTION_RETRIES path = 'admin/mqtt_host' request_url = constants.HOST.rstrip(backslash) + backslash + path log.debug("Get MQTT hostname - url: {}".format(request_url)) while retry_cnt > 0: log.debug('Sending HTTP {} request - url: {} ' 'headers: {}'.format('get', request_url, self.request_header)) response = requests.get(url=request_url, headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug("Response status code received: {}".format( response.status_code)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) if 'mqtt_host' in response: log.debug("Response mqtt hostname: {}".format( response['mqtt_host'])) return response['mqtt_host'] log.info("Retrying...No of retries left: {}".format( str(retry_cnt - 1))) retry_cnt -= 1 time.sleep(5) return False except SSLError as ssl_err: log.error(ssl_err) except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) except RequestException as err: log.error(err) except Exception as req_exc_err: raise Exception(req_exc_err)
def generate_devicecert(outdir, ca_cert, ca_private_key, common_name=None): ''' Generate Device Certificate :param outdir: Output Directory :type outdir: str :param ca_cert: CA Certificate :type ca_cert: x509 Certificate :param ca_private_key: CA Private Key :type ca_private_key: RSA Private Key :param common_name: Common Name :type common_name: str ''' try: log.debug("Generating device cert") log.debug("Generating private key") private_key = generate_private_key() if not private_key: return False, False log.debug("Private key generated") log.debug("Generating CSR") csr = generate_csr(private_key, str(common_name)) if not csr: log.info("Failed to generate CSR") return False, False log.debug("CSR generated") dev_cert = _generate_cert(subject_name=csr.subject, issuer_name=ca_cert.subject, public_key=csr.public_key(), ca_key=ca_private_key) if not dev_cert: log.info("Certificate Not Generated") return False, False log.debug("Device certificate generated successfully") return dev_cert, private_key except Exception as err: raise Exception(err)
def get_register_device_cert_status(vars=None): ''' Get Status of Device Certificate Registration Request :param vars: `requestid` as key - Request Id of device certificate registration request :type vars: str :raises Exception: If there is any exception while getting device certificate registration status KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Get register device cert status") ret_status = _cli_arg_check(vars['requestid'], '--requestid <requestid>') if not ret_status: return _print_keyboard_interrupt_message() # Get current login session token # Re-login if session expired session = Session() token = session.get_access_token() if not token: log.error("Get device certificate registration request failed") return node_mfg = Node_Mfg(token) # Register Device Certificate cert_register_status = node_mfg.get_register_cert_status( vars['requestid']) log.info("Device certificate registration status: {}".format( cert_register_status)) return except KeyboardInterrupt: log.error("\nRegister device certificate failed") except Exception as e: log.error("Error: {}".format(e))
def get_register_cert_status(self, request_id): ''' Register device certificates :param request_id: Request Id of device certificate registration request :type request_id: str ''' try: backslash = '/' log.info("Getting device certificate registration status") path = 'admin/node_certificates/register' query_params = {'request_id': request_id} request_url = constants.HOST.rstrip(backslash) + backslash + path log.debug("Register Certificate - url: {} params: {}".format( request_url, query_params)) log.debug('Sending HTTP {} request - url: {} params: {} ' 'headers: {}'.format('get', request_url, query_params, self.request_header)) # Send query params in HTTP GET Request response = requests.get(url=request_url, params=query_params, headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug("Response status code received: {}".format( response.status_code)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) log.debug("Current status: {:<3}".format(response['status'])) return response['status'] except SSLError as ssl_err: log.error(ssl_err) except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) except Exception as req_exc_err: raise Exception(req_exc_err)
def upload_cert(upload_url, filename): ''' Upload Certificate file to AWS S3 Bucket :param upload_url: URL to upload file to :type upload_url: str :param filename: Name of file to upload :type filename: str ''' try: response = None log.info("Uploading certificate file: {}".format(filename)) while True: try: headers = {'Content-type': 'application/octet-stream'} log.debug("Upload Certificate - url: {} filename: {}".format( upload_url, filename)) with open(filename, "rb") as f: response = requests.put(url=upload_url, data=f, headers=headers) response.raise_for_status() except requests.exceptions.SSLError: raise(SSLError()) except (ConnectionError): log.error(NetworkError()) except RequestException as req_exc_err: log.error(req_exc_err) if response: log.debug("Response received: {}".format(response)) if response.status_code != 200: break return True else: log.info("Retrying...") time.sleep(5) except Exception as err: raise Exception(err)
def _extra_config_files_checks(outdir, extra_config, extra_values, file_id): log.debug("Extra config file checks") set_to_false = None if extra_config and not extra_values: log.info('ADDITIONAL_VALUES file must also be provided in config ' 'alongwith ADDITIONAL_CONFIG file.') set_to_false = False if file_id and file_id in ['node_id']: log.info('`node_id` is the default fileid. ' 'Any new fileid provided as input must be a key in the ' 'ADDITIONAL_VALUES file provided in config.') set_to_false = False if file_id and file_id not in ['node_id'] and not extra_values: log.info( 'Fileid provided must have corresponding values in ADDITIONAL_VALUES file in config. ' 'Please provide ADDITIONAL_VALUES file in config.') set_to_false = False ''' if extra_values and file_id and file_id not in ['node_id'] and not extra_config: log.info('Fileid provided must be a config key. Please provide ADDITIONAL_CONFIG file ' 'alongwith ADDITIONAL_VALUES file in config.') set_to_false = False ''' if extra_config or extra_values: log.debug("Verifying mfg files input") # Verify mfg files verify_mfg_files(outdir, extra_config, extra_values, file_id) if set_to_false is False: return False return True
def _set_data(node_count, common_outdir): # Get current login session token # Re-login if session expired log.debug("Set data") session = Session() token = session.get_access_token() if not token: return None, None node_mfg = Node_Mfg(token) log.debug('Generating node ids for ' 'number of nodes: {}'.format(node_count)) # Generate <node_count> node ids node_id_file_url = node_mfg.gen_node_id(node_count) if not node_id_file_url: log.error("Generate node ids failed") return None, None # Download node ids file from url log.info("Downloading node ids file") node_id_file_data = download_from_url(node_id_file_url) if not node_id_file_data: log.error("Download file from url failed") return None, None # Save node ids data received into a file node_ids_file = save_to_file(node_id_file_data, common_outdir, filename_prefix="node_ids") if not node_ids_file: return None, None log.info("Node ids file saved at location: {}".format(node_ids_file)) # Save mqtt endpoint into a file endpoint = node_mfg.get_mqtthostname() endpoint_file = save_to_file(endpoint, common_outdir, dest_filename=MQTT_ENDPOINT_FILENAME) if not endpoint_file: return None, None log.info("Endpoint saved at location: {}".format(endpoint_file)) return node_ids_file, endpoint_file
def register_cert_req(self, filename, md5_checksum, expected_resp='request_id'): ''' Request to register device certificates :param filename: Filename of uploaded device certificates file :type filename: str :param md5_checksum: MD5 Checksum of file :type md5_checksum: str :param expected_resp: Data expected to be present in response :type expected_resp: str ''' try: backslash = '/' log.debug("Sending request to register certificate") retry_cnt = MAX_HTTP_CONNECTION_RETRIES err_status_key = "status" path = 'admin/node_certificates/register' request_url = constants.HOST.rstrip(backslash) + backslash + path request_body = {'file_name': filename, 'file_md5': md5_checksum} log.debug('Register Certificate Request - url: {} ' 'req_body: {}'.format(request_url, request_body)) while retry_cnt > 0: try: # Send HTTP POST Request log.debug('Sending HTTP {} request - url: {} data: {} ' 'headers: {}'.format('post', request_url, json.dumps(request_body), self.request_header)) response = requests.post(url=request_url, data=json.dumps(request_body), headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug('Response status code received: {}'.format( response.status_code)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) if 'status' in response: log.debug("Response status: {}".format( response['status'])) if 'success' in response['status']: log.debug('Expected response {} ' 'received in response: {}'.format( expected_resp, response)) log.debug("Expected response: {}".format( response[expected_resp])) return response[expected_resp] elif 'failure' in response['status']: log.debug('Request failed: ' 'Response received: {}'.format(response)) log.error('Status: {} \n {}'.format( response[err_status_key], response['description'])) return False except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) log.info("Current status: {}".format(response['status'])) log.debug("Retrying...No of retries left: {}".format( str(retry_cnt - 1))) retry_cnt -= 1 time.sleep(5) return None except SSLError as ssl_err: log.error(ssl_err) except Exception as req_exc_err: raise Exception(req_exc_err)
def generate_ca_cert(vars=None, outdir=None, common_outdir=None, cli_call=True): ''' Generate CA Certificate :param vars: `outdir` as key - Output directory to save generated CA Certificate, defaults to current directory :type vars: str :raises Exception: If there is any exception while generating CA Certificate KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Generate CA certificate") if not outdir: # Set output dirname outdir = _set_output_dir(vars['outdir']) if not common_outdir: # Create output directory for all common files generated common_outdir = _gen_common_files_dir(outdir) # Set CA cert and CA key filepath cacert_filepath = os.path.join(common_outdir, CACERT_FILENAME) cakey_filepath = os.path.join(common_outdir, CA_KEY_FILENAME) if cli_call: _print_keyboard_interrupt_message() log.info('Files generated will be stored ' 'in directory: {}'.format(outdir)) # Set CA cert input config menu cacert_cfg_menu = { "country_name": "Country Name (2 letter code) []:", "state_name": "State or Province Name (full name) []:", "locality_name": "Locality Name (eg, city) []:", "org_name": "Organization Name (eg, company) []:", "org_unit_name": "Organizational Unit Name (eg, section) []:", "common_name": "Common Name (eg, fully qualified host name) []:", "email_addr": "Email Address []:" } # Initialise CA cert config data ca_cert_cfg = { "country_name": "", "state_name": "", "locality_name": "", "org_name": "", "org_unit_name": "", "common_name": "", "email_addr": "" } print('\nPlease enter information which will be ' 'incorporated in your CA Certificate.\n' 'To leave the field blank, press Enter.\n') # Get CA Certificate info from user ca_cert_cfg_values = _get_cacert_user_input(ca_cert_cfg, cacert_cfg_menu) # Generate CA Private Key ca_private_key = generate_private_key() if not ca_private_key: log.error("Failed to generate private key") return # Save CA Private Key into a file ret_status = save_key(ca_private_key, cakey_filepath) if not ret_status: return # Generate CA Certificate cacert = generate_cacert(ca_cert_cfg_values, ca_private_key) if not cacert: print("Failed to generate CA certificate") return log.info('CA Certificate generated successfully ' 'in directory: {}\n'.format(common_outdir)) # Save CA Certificate into a file cacert_filepath = os.path.join(common_outdir, CACERT_FILENAME) ret_status = save_cert(cacert, cacert_filepath) if not ret_status: return if cli_call: log.info('You can now run: \npython rainmaker_admin_cli.py certs ' 'devicecert generate -h ' '(Generate Device Certificate(s))') else: return cacert, ca_private_key except KeyboardInterrupt: log.error("\nCA Certificate Not Generated") except Exception as e: log.error("Error: {}".format(e))
def get_node_id_req(self, node_cnt, expected_resp=None): ''' Request to get list of node ids :param node_cnt: Number of node ids to get :type node_cnt: int :param expected_resp: Data expected to be present in response :type expected_resp: str ''' try: backslash = '/' retry_cnt = MAX_HTTP_CONNECTION_RETRIES log.debug("Retry count set to: {}".format(retry_cnt)) err_status_key = "status" err_description_key = "description" path = 'admin/node_ids' request_url = constants.HOST.rstrip(backslash) + backslash + path request_body = {'node_count': node_cnt} log.debug('Request parameters set: request_url: {} ' 'request_body: {}'.format(request_url, request_body)) while retry_cnt > 0: try: log.debug("Retry Count: {}".format(retry_cnt)) # Send HTTP POST Request log.debug('Sending HTTP {} request - url: {} data: {} ' 'headers: {}'.format('post', request_url, json.dumps(request_body), self.request_header)) response = requests.post(url=request_url, data=json.dumps(request_body), headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug('Response status code ' 'received: {}'.format(response.status_code)) response = json.loads(response.text) log.debug("HTTP Response received: {}".format(response)) if expected_resp in response: log.debug('Expected response {} exists ' 'in response'.format(expected_resp)) return response[expected_resp] elif err_status_key in response: log.debug('Request failed: ' 'response received: {}'.format(response)) log.error("Status: {} \n{}".format( response[err_status_key], response[err_description_key])) return None except NetworkError as net_err: log.info(net_err) except RequestTimeoutError as req_err: log.info(req_err) log.info('Retrying...No of retries left: {}'.format( str(retry_cnt - 1))) retry_cnt -= 1 time.sleep(5) return None except SSLError as ssl_err: log.error(ssl_err) except Exception as err: raise Exception(err)
def gen_and_save_certs(ca_cert, ca_private_key, input_filename, file_id, outdir, endpoint_file, prov_type): ''' Generate and save device certificate :param ca_cert: CA Certificate :type ca_cert: x509 Certificate :param ca_private_key: CA Private Key :type ca_private_key: RSA Private Key :param input_filename: Name of file containing Node Id's :type input_filename: str :param file_id: File Identifier :type file_id: str :param outdir: Output Directory :type outdir: str :param endpoint_file: Endpoint filename :type endpoint_file: str ''' file_id_suffix = None max_filename_len = 6 cnt = 1 step_cnt = 100 extra_keys = None extra_values_file_ptr = None log.debug("File Id recieved as user input: {}".format(file_id)) try: # Init dir generate node_details_outdir, common_outdir, qrcode_outdir = _init_dir(outdir) # Init file generate dest_filename = _init_file(common_outdir) # Init Certs files dest_csv_file = _certs_files_init(dest_filename) # Get extra values filename extra_values_filename = _get_extra_values_filename() if extra_values_filename: # Get extra values file and file headers extra_values_file_ptr, header = _read_extra_values_file_header( extra_values_filename) # Get extra values keys if exists extra_keys = _get_extra_values_keys(header) # Create the headers for the Manufacturing CSV config file dest_config_filename, dest_values_filename = _mfg_files_init( common_outdir, extra_keys) curr_extra_values = None # Print info log.info("\nRandom info will be saved at location: {}".format( node_details_outdir)) log.info("QR code payload will be saved at location: {}".format( node_details_outdir)) log.info("QR code image(png) will be saved at location: {}".format( qrcode_outdir)) log.info("\nGenerating device certificates") # Get Node Ids list from file node_id_list = get_nodeid_from_file(input_filename) if not node_id_list: print("Node ids not found in file: {}".format(input_filename)) return False node_id_list = [i for i in node_id_list if i] # Generate and save cert for each node id for node_id in node_id_list: # Remove any spaces/newlines which may exist # at the start or end of the node id string node_id = node_id.strip() log.debug("Current node id: {}".format(node_id)) # Set file id suffix if file_id == 'node_id': file_id_suffix = node_id # Get the values in ADDITIONAL_VALUES file if extra_values_filename: curr_extra_values = _get_curr_extra_value( extra_values_file_ptr) # Set file id suffix key_value_data = list( zip_longest(extra_keys, curr_extra_values)) log.debug("Current key-value data: {}".format(key_value_data)) for item in key_value_data: if item[0] == file_id: file_id_suffix = item[1] log.debug( "File Id suffix set to: {}".format(file_id_suffix)) if not file_id_suffix: raise Exception( '<count> provided is not equal to ' 'number of values for fileid: {} in file: {} '. format(file_id, extra_values_filename)) # Create directory for node details for specific node id zeros_prefix_len = max_filename_len - len(str(cnt)) zero_prefix_str = '0' * zeros_prefix_len node_id_dir_str = 'node-' + zero_prefix_str + str( cnt) + "-" + file_id_suffix node_id_dir = os.path.join(node_details_outdir, node_id_dir_str) if not os.path.isdir(node_id_dir): distutils.dir_util.mkpath(node_id_dir) log.debug("Directory created: {}".format(node_id_dir)) # Set destination filename to save device certificates generated cert_dest_filename = _set_filename(filename_prefix='node', outdir=node_id_dir, ext=".crt") if not cert_dest_filename: return False # Set destination filename to save private keys # of certificates generated key_dest_filename = _set_filename(filename_prefix='node', outdir=node_id_dir, ext=".key") if not key_dest_filename: return False log.debug("Saving Key for Node Id: {} at location: {}".format( node_id, key_dest_filename)) log.debug("Generating device certificate for node id: {}".format( node_id)) # Get random info random_hex_str, random_str_file = _gen_random_info(node_id_dir) if not random_hex_str and not random_str_file: return # Print status _print_status(cnt, step_cnt, msg='Random str (used as PoP) generated') # Create values file for input to # Manufacturing Tool to generate binaries _create_values_file(dest_values_filename, cnt, node_id, endpoint_file, cert_dest_filename, key_dest_filename, random_str_file, curr_extra_values) # Generate device certificate dev_cert, priv_key = generate_devicecert(outdir, ca_cert, ca_private_key, common_name=node_id) if not dev_cert and not priv_key: return False log.debug('Saving Certificate for Node Id: {} ' 'at location: {}'.format(node_id, cert_dest_filename)) # Save certificate ret_status = save_cert(dev_cert, cert_dest_filename) if not ret_status: return False # Save private key ret_status = save_key(priv_key, key_dest_filename) if not ret_status: return False # Save node ids and certs together in a csv file # (used to upload and register the certificates) log.debug("Saving Node Id and Certificate to file: {}".format( dest_filename)) ret_status = _save_nodeid_and_cert_to_file(node_id, dev_cert, dest_csv_file) if not ret_status: return False log.debug("Number of certificates generated and saved") _print_status(cnt, step_cnt, msg='Certificates generated') # Generate QR code if prov_type: # Generate provisioning data # QR code image and str prov_status = _gen_prov_data(node_id_dir, node_id_dir_str, qrcode_outdir, random_hex_str, prov_type) if not prov_status: return # Print QR code status _print_status(cnt, step_cnt, msg='QRcode payload and image generated') cnt += 1 log.info("\nTotal certificates generated: {}".format(str(cnt - 1))) # Cleanup dest_csv_file.seek(0) dest_csv_file.close() if extra_values_filename: extra_values_file_ptr.seek(0) extra_values_file_ptr.close() log.info("Device certificates generated successfully") return dest_filename except FileError as file_err: log.error(file_err) except Exception as err: raise Exception(err)
def generate_device_cert(vars=None): ''' Generate Device Certificate :param vars: `count` as key - Number of Node Ids for generating certificates :type vars: str :param vars: `fileid` as key - File Identifier :type vars: str :param vars: `cacertfile` as key - Name of file containing CA Certificate :type vars: str :param vars: `cakeyfile` as key - Name of file containing CA Private Key :type vars: str :param vars: `outdir` as key - Output directory to save generated Device Certificate, defaults to current directory :type vars: str :raises Exception: If there is any exception while generating Device Certificate(s) KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Generate device certificates") node_count = int(vars['count']) ret_status = _cli_arg_check(node_count, '--count <count>', err_msg='<count> must be > 0') if not ret_status: return # Init file_id = vars['fileid'] if len(file_id) == 0: file_id = None prov_type = None if vars['prov']: prov_type = vars['prov'] # Set output dirname outdir = _set_output_dir(vars['outdir']) # Extra config files checks extra_config = get_param_from_config('ADDITIONAL_CONFIG') extra_values = get_param_from_config('ADDITIONAL_VALUES') ret_status = _extra_config_files_checks(outdir, extra_config, extra_values, file_id) if not ret_status: return # Fileid checks ret_status = _fileid_check(file_id, node_count, extra_values) if not ret_status: return # Set default file id if not file_id: file_id = 'node_id' # Create output directory for all common files generated common_outdir = _gen_common_files_dir(outdir) # Generate CA Cert and CA Key ca_cert_filepath = vars['cacertfile'] ca_key_filepath = vars['cakeyfile'] log.debug("CA Cert filename input: {}".format(ca_cert_filepath)) log.debug("CA Key filename input: {}".format(ca_key_filepath)) if not ca_cert_filepath and not ca_key_filepath: ca_cert, ca_private_key = generate_ca_cert( vars=vars, outdir=outdir, common_outdir=common_outdir, cli_call=False) if ca_cert_filepath and not ca_key_filepath: raise Exception("CA key file is not provided") if ca_key_filepath and not ca_cert_filepath: raise Exception("CA cert file is not provided") _print_keyboard_interrupt_message() log.info('Files generated will be stored ' 'in directory: {}'.format(outdir)) # Get and save CA Certificate from file if len(ca_cert_filepath) != 0: ca_cert = _get_and_save_ca_cert_from_input(common_outdir, ca_cert_filepath) # Get and save CA Private Key from file if len(ca_key_filepath) != 0: ca_private_key = _get_and_save_ca_key_from_input( common_outdir, ca_key_filepath) # Set data node_ids_file, endpoint_file = _set_data(node_count, common_outdir) if not node_ids_file and not endpoint_file: raise Exception("") # Generate Device Cert and save into file certs_dest_filename = gen_and_save_certs(ca_cert, ca_private_key, node_ids_file, file_id, outdir, endpoint_file, prov_type) if not certs_dest_filename: log.error("Generate device certificate failed") return log.info('\nNode Ids and device certificates saved at ' 'location: {}'.format(certs_dest_filename)) # Generate binaries log.info("\nGenerating binaries for the device certficates generated") gen_cert_bin(outdir, file_id) log.info('\nYou can now run: \npython rainmaker_admin_cli.py certs ' 'devicecert register --inputfile {} ' '(Register Generated Device Certificate(s))'.format( certs_dest_filename)) except KeyboardInterrupt: log.error("\nGenerate device certificate failed") except Exception as err: log.error("Generate device certificate failed") if len(str(err)) > 0: log.error("Error: {}".format(err))
def get_cert_upload_url(self, cert_filename): ''' Get URL to upload device certificates :param cert_filename: Filename having certifcates :type cert_filename: str ''' try: backslash = '/' log.info("Get URL for uploading certificates file") retry_cnt = MAX_HTTP_CONNECTION_RETRIES expected_key_in_resp = "url" err_status_key = "status" path = 'admin/node_certificates/register' query_params = {'file_name': cert_filename} request_url = constants.HOST.rstrip(backslash) + backslash + path log.debug('Sending request to get URL ' 'for uploading certificates file ' '- url: {} params: {}'.format(request_url, query_params)) while retry_cnt > 0: try: log.debug('Sending HTTP {} request - url: {} params: {} ' 'headers: {}'.format('get', request_url, query_params, self.request_header)) # Send query params in HTTP GET Request response = requests.get(url=request_url, params=query_params, headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug("Response status code received: {}".format( response.status_code)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) if expected_key_in_resp in response: log.debug('Expected key: {} present in ' 'response: {}'.format( expected_key_in_resp, response)) log.info('URL for uploading certificates file ' 'received successfully') log.debug("URL received: {}".format( response[expected_key_in_resp])) return response[expected_key_in_resp] elif err_status_key in response: log.debug('Request failed: response ' 'received: {}'.format(response)) log.error("Status: {} \n {}".format( response[err_status_key], response['description'])) return None except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) log.info('Retrying...No of retries ' 'left: {}'.format(str(retry_cnt - 1))) retry_cnt -= 1 time.sleep(5) return None except SSLError as ssl_err: log.error(ssl_err) except Exception as req_exc_err: raise Exception(req_exc_err)
def register_device_cert(vars=None): ''' Register Uploaded Device Certificate :param vars: `inputfile` as key - Name of file containing node ids and device certificates :type vars: str :raises Exception: If there is any exception while registering Device Certificate(s) KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Register device certificate") ret_status = _cli_arg_check(vars['inputfile'], '--inputfile <csvfilename>') if not ret_status: return is_valid_type = _check_file_type(vars['inputfile']) if not is_valid_type: return _print_keyboard_interrupt_message() # Get current login session token # Re-login if session expired session = Session() curr_email_id = session.get_curr_user_creds() token = session.get_access_token() if not token: log.error("Register device certificate failed") return # Get filename from input path basefilename = os.path.basename(vars['inputfile']) node_mfg = Node_Mfg(token) # Get URL to upload Device Certificate to cert_upload_url = node_mfg.get_cert_upload_url(basefilename) if not cert_upload_url: log.error("Upload Device Certificate Failed.") return # Upload Device Certificate file to S3 Bucket cert_upload = upload_cert(cert_upload_url, vars['inputfile']) if not cert_upload: log.error("Failed to upload Device Certificates") return else: log.info("Device certificate uploaded") # Get MD5 Checksum for input file md5_checksum = _get_md5_checksum(vars['inputfile']) # Register Device Certificate request_id = node_mfg.register_cert_req(basefilename, md5_checksum) if not request_id: log.error("Request to register device certificate failed") return else: log.info('Request to register device certificate is successful\n') log.info('Certificate registration will take some time\n' 'You will receive the status on ' 'your email-id: {}'.format(curr_email_id)) log.info( '\nYou can also run following command to check status: \n' 'python rainmaker_admin_cli.py certs devicecert getcertstatus ' '--requestid {} ' '(Get Device Certificate Registration ' 'Status)'.format(request_id)) except KeyboardInterrupt: log.error("\nRegister device certificate failed") except Exception as e: log.error("Error: {}".format(e))
def login(self, password=None): """ Login to user with given password :param password: Password of User :type password: str """ try: backslash = '/' socket.setdefaulttimeout(10) expected_resp = ["idtoken", "accesstoken", "refreshtoken"] # Get password from user if password is None: log.debug("Get password from user") password = getpass.getpass("Password:"******"Password received") # Set HTTP Request path = 'login/' login_info = {'user_name': self.__email, 'password': password} login_url = constants.HOST.rstrip(backslash) + backslash + path log.debug('Sending HTTP POST Request - login url:{} ' 'request body: {}'.format(login_url, json.dumps(login_info))) # Send HTTP POST Request log.debug('Sending HTTP {} request - url: {} data: {} ' 'headers: {}'.format('post', login_url, json.dumps(login_info), self.request_header)) response = requests.post(url=login_url, data=json.dumps(login_info), headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) # Check response if 'status' in response: log.debug("Response status: {}".format(response['status'])) if 'success' in response['status']: for item in expected_resp: if item not in response: log.error('Expected response {} not found in ' 'response: {}'.format(item, response)) return False else: log.debug('Expected response {} received in ' 'response: {}'.format(item, response)) return response elif 'failure' in response['status']: log.info(response['description']) return False else: log.debug( "Login API HTTP status not in success/failure. Response received: {}" .format(response)) return False except SSLError as ssl_err: log.error(ssl_err) except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) except RequestException as req_exc_err: log.error(req_exc_err) except Exception as err: log.error(err)
def login(vars=None): ''' User login :param vars: `email` as key - Email of user to login :type vars: str :raises Exception: If there is any exception while logging in KeyboardInterrupt: If there is a keyboard interrupt by user :return: None on Failure :rtype: None ''' try: log.debug("Login command") ret_server_status = _verify_serverconfig_exists() if not ret_server_status: return ret_status = _cli_arg_check(vars['email'], '--email <emailid>') if not ret_status: return _print_keyboard_interrupt_message() # Get current user email-id session = Session() curr_email_id = session.get_curr_user_creds() # Remove current login config if exists config = configmanager.Config() # Current email creds exist if curr_email_id: ret_status = config.remove_curr_login_config(email=curr_email_id) if not ret_status: return # User login user = User(vars['email']) # Login API call user_login_data = user.login() if not user_login_data: log.error("Login failed.") return else: log.info("Login successful") # Save new user login config ret_status, cfg_file = config.save_config(user_login_data) if not ret_status: log.error('Failed to save login config ' 'to file {}'.format(cfg_file)) return else: log.info("Saved new login config in file: {}".format(cfg_file)) log.info('\nYou can now run: \npython rainmaker_admin_cli.py certs ' 'cacert generate -h (Generate CA Certificate)' '\n\tor\npython rainmaker_admin_cli.py certs devicecert ' 'generate -h (Generate Device Certificate(s))') except KeyboardInterrupt: log.error("\nLogin Failed") except Exception as e: log.error("Error: {}".format(e))
def get_access_token(self): ''' Get Access Token ''' try: log.debug("Getting access token") config = Config() config_data = config.read_config() if not config_data: log.info("User is not logged in. Please login to continue") log.debug('User config data not found. ' 'Please login to continue') return False log.debug("Config data: {}".format(config_data)) if 'accesstoken' not in config_data: log.error('Access Token not found in current login ' 'config data from ' 'file: {}'.format(config.config_file)) return False access_token = config_data['accesstoken'] if not self.__is_valid_token(access_token): log.info('Previous Session expired. Initialising new session') id_token = config_data['idtoken'] email_id = self.get_token_attribute('email', id_token) log.debug("Email Id: {}".format(email_id)) if not email_id: log.debug("Failed to get email attribute from payload.") return False valid_ver_status = self.__is_valid_version() if valid_ver_status is False: log.error(InvalidApiVersionError()) return False elif valid_ver_status is None: return False refresh_token = config_data['refreshtoken'] user = User(email_id) access_token, id_token = user.get_new_token(refresh_token) log.debug('New config data received - access token: {} ' 'id token: {}'.format(access_token, id_token)) if not access_token and not id_token: log.debug("Error getting new user token") log.info( "Previous Session expired. Cannot extend session. Please login to continue" ) return False new_config = {} key_text = str('accesstoken') new_config[key_text] = access_token key_text = str('idtoken') new_config[key_text] = id_token key_text = str('refreshtoken') new_config[key_text] = refresh_token log.debug("New config data: {}".format(new_config)) ret_status = config.update_config(new_config) log.debug("Config data update status: {}".format(ret_status)) if not ret_status: log.debug("Failed to update config.") return False log.debug('Previous Session expired. New session initialised.') log.debug("Current Session is valid") return access_token except Exception as err: log.debug("Error while getting access token") return False
def _print_keyboard_interrupt_message(): log.info("Press Ctrl-C to abort")
def gen_node_id(self, node_count): ''' Generate list of node ids :param node_cnt: Number of node ids to get :type node_cnt: int ''' try: backslash = '/' req_id = None log.info("Sending request for generating node ids: {}".format( node_count)) expected_resp = 'request_id' log.debug('Sending request for node ids for number of nodes: {}. ' 'Expected response: {}'.format(node_count, expected_resp)) req_id = self.get_node_id_req(node_count, expected_resp=expected_resp) if not req_id: log.debug( "Expected response: {} not found.".format(expected_resp)) return False log.info('Request for generating ' 'node ids: {} is successful'.format(node_count)) retry_cnt = MAX_HTTP_CONNECTION_RETRIES expected_key_in_resp = "url" path = 'admin/node_ids' query_params = {'request_id': req_id} request_url = constants.HOST.rstrip(backslash) + backslash + path log.debug('Sending GET HTTP Request - request url: {} ' 'query params: {}'.format(request_url, query_params)) log.info('Sending request for getting {} ' 'for node ids file'.format(expected_key_in_resp)) while retry_cnt > 0: try: log.debug('Sending HTTP {} request - url: {} params: {} ' 'headers: {}'.format('get', request_url, query_params, self.request_header)) # Send query params in HTTP GET Request response = requests.get(url=request_url, params=query_params, headers=self.request_header, verify=configmanager.CERT_FILE, timeout=(5.0, 5.0)) log.debug("Response status code received: {}".format( response.status_code)) response = json.loads(response.text) log.debug("Response received: {}".format(response)) curr_time = time.time() timestamp = datetime.datetime.fromtimestamp( curr_time).strftime('%H:%M:%S') log.info("[{:<6}] Current status: {:<3}".format( timestamp, response['status'])) if 'success' in response['status']: log.debug("Response status: {}".format( response['status'])) if expected_key_in_resp not in response: raise InvalidJSONError log.info("Node ids file url received successfully") log.debug("URL received: {}".format( response[expected_key_in_resp])) return response[expected_key_in_resp] elif 'in_progress' in response['status']: time.sleep(5) continue elif 'failure' in response['status']: log.debug('Request failed: response ' 'received: {}'.format(response)) log.error("Status: {} \n {}".format( response['status'], response['description'])) return None except NetworkError as net_err: log.error(net_err) except RequestTimeoutError as req_err: log.error(req_err) log.info('Retrying...No of retries left: {}'.format( str(retry_cnt - 1))) retry_cnt -= 1 time.sleep(5) return None except InvalidJSONError as json_err: log.error(json_err) except SSLError as ssl_err: log.error(ssl_err) except Exception as err: raise Exception(err)