예제 #1
0
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
예제 #2
0
def test(vars=None):
    """
    Check user node mapping

    :param vars:
        `addnode` as key - Node ID of node to be mapped to user,\n
        defaults to `None`
    :type vars: dict

    """
    node_id = vars['addnode']
    if node_id is None or not vars.get('addnode'):
        print('Error: The following arguments are required: --addnode\n'
              'Check usage: rainmaker.py [-h]\n')
        sys.exit(0)
    node_object = node.Node(node_id, session.Session())
    request_id, secret_key = add_node(node_object)
    config = configmanager.Config()
    user_id = config.get_user_id()
    print('Use following command on node simulator or '
          'node CLI to confirm user node mapping:')
    print(" add-user " + user_id + " " + secret_key)
    print("---------------------------------------------------")
    print("RequestId for user node mapping request : " + request_id)
    check_status(node_object, request_id)
    return
예제 #3
0
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
예제 #4
0
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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
    def login(self, password=None):
        """
        User login to the ESP Rainmaker.

        :param password: Password of user, defaults to `None`
        :type password: str

        :raises NetworkError: If there is a network connection issue
                              during login
        :raises Exception: If there is an HTTP issue during login or
                           JSON format issue in HTTP response
        :raises AuthenticationError: If login failed with the given parameters

        :return: :class:`rmaker_lib.session.Session` on Success
        :rtype: object
        """
        log.info("User login with username : "******"Login request url : " + login_url)
            response = requests.post(url=login_url,
                                     data=json.dumps(login_info),
                                     headers=self.__request_header,
                                     verify=configmanager.CERT_FILE)
            log.debug("Login response : " + response.text)
            response.raise_for_status()
        except requests.exceptions.SSLError:
            raise SSLError
        except requests.exceptions.ConnectionError:
            raise NetworkError
        except Exception:
            raise Exception(response.text)

        try:
            result = json.loads(response.text)
        except Exception as json_decode_err:
            raise json_decode_err

        if 'status' in result and result['status'] == 'success':
            log.info("Login successful.")
            config_data = {}
            config_data['idtoken'] = result['idtoken']
            config_data['refreshtoken'] = result['refreshtoken']
            config_data['accesstoken'] = result['accesstoken']
            configmanager.Config().set_config(config_data)
            return session.Session()
        raise AuthenticationError
예제 #9
0
def list_sharing_details(node_id=None, primary_user=False, request_id=None, list_requests=False):
    """
    List sharing details of all nodes associated with user
    or List pending requests
    
    :param vars: `node_id` as key - Node Id of the node(s)
                 (if not provided, is set to all nodes associated with user)
    :type vars: str

    :param vars: `primary_user` as key - User is primary or secondary
                 (if provided, user is primary user)
    :type vars: bool

    :param vars: `request_id` as key - Id of sharing request
    :type vars: str

    :param vars: `list_requests` as key -
                 If True, list pending requests
                 If False, list sharing details of nodes
    :type vars: bool

    :raises Exception: If there is an issue
                       while listing details

    :return: API response
    :rtype: dict
    """
    node_obj = node.Node(node_id, session.Session())
    log.debug("Node id received from user: {}".format(node_id))

    # Set data for listing pending requests
    if list_requests:
        # Create API query params
        api_params = {}
        if request_id:
            api_params['id'] = request_id
        api_params['primary_user'] = "******".format(primary_user)

        node_json_resp = node_obj.get_shared_nodes_request(api_params)
        log.debug("List sharing request response: {}".format(node_json_resp))
    else:
        # Get sharing details of all nodes associated with user
        # API
        node_json_resp = node_obj.get_sharing_details_of_nodes()
        log.debug("Get shared nodes response: {}".format(node_json_resp))

    return node_json_resp
예제 #10
0
def remove_sharing(nodes=None, user=None, request_id=None):
    """
    Remove user from shared nodes or
    Remove sharing request

    :param vars: `nodes` as key - Node Id for the node
    :type vars: str

    :param vars: `user` as key - User name
    :type vars: str

    :param vars: `request_id` as key - Id of sharing request
    :type vars: str

    :raises Exception: If there is an issue
                       while remove operation

    :return: API response
    :rtype: dict
    """
    print('\nPlease make sure current (logged-in) user is Primary user\n')

    node_json_resp = None
    node_obj = node.Node(None, session.Session())
    if request_id:
        # API call to remove the shared nodes request
        node_json_resp = node_obj.remove_shared_nodes_request(request_id)
        log.debug("Remove sharing request response: {}".format(node_json_resp))
    else:
        # Remove any spaces if exist
        node_ids = nodes.strip()

        # Check user input format
        ret_status = _check_user_input(node_ids)
        
        # Create API query params dictionary
        api_params = {}
        api_params['nodes'] = node_ids
        api_params['user_name'] = user
        log.debug("API data set to: {}".format(api_params))
        
        # API call to remove the shared nodes
        node_json_resp = node_obj.remove_user_from_shared_nodes(api_params)
        log.debug("Remove user from shared nodes response: {}".format(node_json_resp))
    
    return node_json_resp
예제 #11
0
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
예제 #12
0
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
예제 #13
0
def sharing_request_op(accept_request=False, request_id=None):
    """
    Accept or decline sharing request
    
    :param vars: `accept_request` as key
                  If true, accept sharing request
                  If false, decline sharing request
    :type vars: bool

    :param vars: `request_id` as key - Id of sharing request
    :type vars: str

    :raises Exception: If there is an issue
                       accepting or declining request

    :return: API response
    :rtype: dict
    """
    log.debug("Accept sharing request")

    print('\nPlease make sure current (logged-in) user is Secondary user\n')

    if accept_request:
        print("Accepting request")
    else:
        print("Declining request")

    # Create API data dictionary
    api_data = {}
    api_data['accept'] = accept_request
    api_data['request_id'] = request_id

    node_obj = node.Node(None, session.Session())
    log.debug("API data set: {}".format(api_data))
    
    # API to accept or decline node sharing request
    node_json_resp = node_obj.request_op(api_data)
    log.debug("Sharing request API response: {}".format(node_json_resp))

    return node_json_resp
예제 #14
0
def add_user_to_share_nodes(nodes=None, user=None):
    """
    Add user to share nodes
    
    :param vars: `nodes` as key - Node Id of the node(s)
    :type vars: str

    :param vars: `user` as key - User name
    :type vars: str

    :raises Exception: If there is an issue
                       while adding user to share nodes

    :return: API response
    :rtype: dict
    """
    log.debug("Adding user to share nodes")

    # Remove any spaces if exist
    nodes = nodes.strip()
    # Check user input format
    ret_status = _check_user_input(nodes)
    # Create list from node ids string
    node_id_list = _set_node_ids_list(nodes)
    log.debug("Node ids list: {}".format(node_id_list))

    log.debug("User name is set: {}".format(user))
    
    # Create API input info
    api_input = {}
    api_input['nodes'] = node_id_list
    api_input['user_name'] = user
    log.debug("API data set: {}".format(api_input))

    # API
    node_obj = node.Node(None, session.Session())
    node_json_resp = node_obj.add_user_for_sharing(api_input)
    log.debug("Set shared nodes response: {}".format(node_json_resp))

    return node_json_resp
예제 #15
0
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
예제 #16
0
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
예제 #17
0
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 provision(vars=None):
    """
    Provisioning of the node.

    :raises NetworkError: If there is a network connection issue
                          during provisioning
    :raises Exception: If there is an HTTP issue during provisioning

    :param vars: `pop` - Proof of Possession of the node, defaults to `None`
    :type vars: dict

    :return: None on Success and Failure
    :rtype: None
    """
    log.info('Provisioning the node.')
    secret_key = str(uuid.uuid4())
    pop = vars['pop']
    try:
        config = configmanager.Config()
        userid = config.get_user_id()
        log.debug('User session is initialized for the user ' + userid)
    except Exception as get_user_id_err:
        log.error(get_user_id_err)
        sys.exit(1)
    try:
        input('Please connect to the wifi PROV_XXXXXX and '
              'Press Enter to continue...')
    except Exception:
        print("Exiting...")
        sys.exit(0)

    node_id = provision_device(TRANSPORT_MODE_SOFTAP, pop, userid, secret_key)
    if node_id is None:
        log.error(PROVISION_FAILURE_MSG)
        return
    log.debug('Node ' + node_id + ' provisioned successfully.')

    print('------------------------------------------')
    input('Please ensure host machine is connected to internet and '
          'Press Enter to continue...')

    retries = MAX_HTTP_CONNECTION_RETRIES
    node_object = None
    while retries > 0:
        try:
            # If session is expired then to initialise the new session
            # internet connection is required.
            node_object = node.Node(node_id, session.Session())
        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
        else:
            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' +
                  '\n' + PROVISION_FAILURE_MSG)
        return

    print('\nAdding User-Node association')
    log.info("Adding User-Node association")

    retries = MAX_HTTP_CONNECTION_RETRIES
    request_id = None
    log.info('Sending User-Node Association Request...')
    while retries > 0:
        print('Sending User-Node Association Request...')
        try:
            request_id = node_object.add_user_node_mapping(secret_key)
        except SSLError:
            log.error(SSLError())
            break
        except (NetworkError, RequestTimeoutError) as conn_err:
            print(conn_err)
            log.warn(conn_err)
        except Exception as mapping_err:
            print(mapping_err)
            log.warn(mapping_err)
            break
        else:
            if request_id is not None:
                log.debug('User-Node mapping added successfully '
                          'with request_id '
                          + request_id)
                break

        retries -= 1
        if retries:
            print("Retries left:", retries)
            log.info("Retries left: " + str(retries))
            time.sleep(5)

    if request_id is None:
        log.error('User-Node Association Request...Failed\n' +
                  '\n' + PROVISION_FAILURE_MSG)
        return

    print('User-Node Association Request...Success')
    log.info('User-Node Association Request...Success')

    retries = MAX_HTTP_CONNECTION_RETRIES
    status = None
    log.info('Checking User-Node Association Status...')
    while retries > 0:
        print('Checking User-Node Association Status...')
        try:
            status = node_object.get_mapping_status(request_id)
        except SSLError:
            log.error(SSLError())
            break
        except (NetworkError, RequestTimeoutError) as conn_err:
            print(conn_err)
            log.warn(conn_err)
            status = None
        except Exception as mapping_status_err:
            print(mapping_status_err)
            log.warn(mapping_status_err)
            break
        else:
            if status == 'requested':
                print('User-Node Association Status - Requested'
                      '\n')
                log.debug('User-Node Association Status - Requested'
                          '\n')
            elif status == 'confirmed':
                print('User-Node Association Status - Confirmed'
                      '\nProvisioning was Successful.')
                log.debug('User-Node Association Status - Confirmed'
                          '\nProvisioning was Successful.')
                break
            elif status == 'timedout':
                print('User-Node Association Status - Timedout')
                log.debug('User-Node Association Status - Timedout')
                break
            elif status == 'discarded':
                print('User-Node Association Status - Discarded')
                log.debug('User-Node Association Status - Discarded')
                break
            else:
                log.debug('User-Node Association Status - ' + status)
                break

        if status not in ["requested"]:
            retries -= 1
            if retries:
                print("Retries left:", retries)
                log.info("Retries left: " + str(retries))
        time.sleep(5)

    if status not in ["confirmed"]:
        log.error('Checking User-Node Association Status...Failed.\n'
                  '\nCould not confirm User-Node Association Status. '
                  '\nPlease use cli command '
                  '`python3 rainmaker.py getnodes` to confirm.')
        return
    return
예제 #19
0
def claim(port):
    """
    Claim the node connected to the given serial port
    (Get cloud credentials)

    :param port: Serial Port
    :type port: str

    :raises Exception: If there is an HTTP issue while claiming
            SSLError: If there is an issue in SSL certificate validation
            ConnectionError: If there is network connection issue

    :return: None on Success
    :rtype: None
    """
    try:
        node_id = None
        node_info = None
        hmac_challenge = None
        claim_verify_data = None
        claim_initiate_url = CLAIM_INITIATE_URL
        claim_verify_url = CLAIM_VERIFY_URL
        private_key = None
        curr_claim_data = None
        user_whitelist_err_msg = ('user is not allowed to claim esp32 device.'
                                  ' please contact administrator')

        config = configmanager.Config()
        userid = config.get_user_id()

        creds_dir = Path(
            path.expanduser(
                str(Path(path.expanduser(configmanager.HOME_DIRECTORY))) +
                '/' +
                str(Path(path.expanduser(configmanager.CONFIG_DIRECTORY))) +
                '/claim_data/' + userid))
        if not creds_dir.exists():
            os.makedirs(path.expanduser(creds_dir))
            log.debug("Creating new directory " + str(creds_dir))

        print("\nClaiming process started. This may take time.")
        log.info("Claiming process started. This may take time.")

        node_platform, mac_addr = get_node_platform_and_mac(esptool, port)
        print("Node platform detected is: ", node_platform)
        print("MAC address is: ", mac_addr)
        log.debug("MAC address received: " + mac_addr)
        log.debug("Node platform detected is: " + node_platform)

        log.info("Creating session")
        curr_session = session.Session()
        header = curr_session.request_header

        start = time.time()

        mac_dir = Path(path.expanduser(str(creds_dir) + '/' + mac_addr))
        if not mac_dir.exists():
            os.makedirs(path.expanduser(mac_dir))
            log.debug("Creating new directory " + str(mac_dir))

        output_bin_filename = mac_addr + '.bin'
        mac_dir_path = str(mac_dir) + '/'

        # Set values
        dest_filedir = mac_dir_path

        # Set csv file data
        node_info_csv = [
            'key,type,encoding,value', 'rmaker_creds,namespace,,',
            'node_id,file,binary,' + dest_filedir + 'node.info',
            'mqtt_host,file,binary,' + dest_filedir + 'endpoint.info',
            'client_cert,file,binary,' + dest_filedir + 'node.crt',
            'client_key,file,binary,' + dest_filedir + 'node.key'
        ]

        # Generate nvs args to be sent to NVS Partition Utility
        nvs_args = SimpleNamespace(input=dest_filedir + 'node_info.csv',
                                   output=output_bin_filename,
                                   size='0x6000',
                                   outdir=dest_filedir,
                                   version=2)

        # Set config mac addr path
        mac_addr_config_path = str(Path(path.expanduser(
            configmanager.CONFIG_DIRECTORY))) + '/claim_data/' +\
            userid +\
            '/' +\
            mac_addr +\
            '/' + output_bin_filename

        # Check if claim data for node exists in CONFIG directory
        log.debug("Checking if claim data for node exists in directory: " +
                  configmanager.HOME_DIRECTORY +
                  configmanager.CONFIG_DIRECTORY)
        curr_claim_data = configmanager.Config().get_binary_config(
            config_file=mac_addr_config_path)
        if curr_claim_data:
            print("\nClaiming data already exists at location: " +
                  dest_filedir)
            log.debug("Claiming data already exists at location: " +
                      dest_filedir)
            log.info("Using existing claiming data")
            print("Using existing claiming data")
            # Flashing existing binary onto node
            print("\nFlashing existing binary onto node\n")
            log.info("Flashing existing binary onto node")
            flash_bin_onto_node(port, esptool,
                                dest_filedir + output_bin_filename)
            log.info("Binary flashed onto node")
            return

        # Generate Key
        log.info("Generate RSA key")
        private_key = rsa.generate_private_key(public_exponent=65537,
                                               key_size=2048,
                                               backend=default_backend())

        log.info("RSA Private Key generated")
        # Set Claim initiate request data
        claim_initiate_data = {"mac_addr": mac_addr, "platform": node_platform}
        claim_init_enc_data = str(claim_initiate_data).replace("'", '"')

        print("Claim initiate started")
        # Sign the CSR using the CA
        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_enc_data) + "headers: " + str(header) +
                      "verify: " + CERT_FILE)
            claim_initiate_response = requests.post(url=claim_initiate_url,
                                                    data=claim_init_enc_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")
            # Get data from response depending on node_platform
            if node_platform == "esp32":
                # Generate CSR with common_name=node_id received in response
                node_id = str(
                    json.loads(claim_initiate_response.text)['node_id'])
                print("Generating CSR")
                log.info("Generating CSR")
                csr = gen_host_csr(private_key, common_name=node_id)
                if not csr:
                    raise Exception("CSR Not Generated. Claiming Failed")
                log.info("CSR generated")
                claim_verify_data = {"csr": csr}
                # Save node id as node info to use while saving claim data
                # in csv file
                node_info = node_id
            else:
                auth_id = str(
                    json.loads(claim_initiate_response.text)['auth_id'])
                hmac_challenge = str(
                    json.loads(claim_initiate_response.text)['challenge'])
                print("Generating CSR")
                log.info("Generating CSR")
                csr = gen_host_csr(private_key, common_name=mac_addr)
                if not csr:
                    raise Exception("CSR Not Generated. Claiming Failed")
                log.info("CSR generated")
                log.info("Getting secret key from device")
                secret_key = get_secret_key(port, esptool)
                log.info("Getting secret key from device")
                log.info("Generating hmac challenge response")
                hmac_challenge_response = gen_hmac_challenge_resp(
                    secret_key, hmac_challenge)
                hmac_challenge_response = hmac_challenge_response.strip('\n')
                log.debug("Secret Key generated: " + secret_key)
                log.debug("HMAC Challenge Response: " +
                          hmac_challenge_response)
                claim_verify_data = {
                    "auth_id": auth_id,
                    "challenge_response": hmac_challenge_response,
                    "csr": csr
                }
                # Save node id as node info to use while saving claim data
                # in csv file
                node_info = mac_addr

            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")
            node_cert = json.loads(claim_verify_response.text)['certificate']
            print("Claim certificate received")
            log.info("Claim certificate received")
        except requests.exceptions.SSLError:
            raise SSLError
        except requests.ConnectionError:
            log.error("Please check the Internet connection.")
            exit(0)

        # Set node claim data
        sys.stdout = StringIO()
        log.info("Getting MQTT Host")
        endpointinfo = node.get_mqtt_host(None)
        log.debug("Endpoint info received: " + endpointinfo)
        sys.stdout = sys.__stdout__

        # Extract private key in bytes from private key object generated
        log.info("Extracting private key in bytes")
        node_private_key = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption())

        # Create files of each claim data info
        print("\nSaving claiming data info at location: ", dest_filedir)
        log.debug("Saving claiming data info at location: " + dest_filedir)
        create_files_of_claim_info(dest_filedir, node_info, node_private_key,
                                   node_cert, endpointinfo, node_info_csv)

        # Run NVS Partition Utility to create binary of node info data
        print("\nGenerating NVS Partition Binary from claiming data: " +
              dest_filedir + output_bin_filename)
        log.debug("Generating NVS Partition Binary from claiming data: " +
                  dest_filedir + output_bin_filename)
        nvs_partition_gen.generate(nvs_args)
        print("\nFlashing onto node\n")
        log.info("Flashing binary onto node")
        flash_bin_onto_node(port, esptool, dest_filedir + output_bin_filename)

        print("Claiming done")
        log.info("Claiming done")
        print("Time(s):" + str(time.time() - start))
    except Exception as err:
        log.error(err)
        sys.exit(err)
예제 #20
0
def provision(vars=None):
    """
    Provisioning of the node.

    :raises NetworkError: If there is a network connection issue
                          during provisioning
    :raises Exception: If there is an HTTP issue during provisioning

    :param vars: `pop` - Proof of Possession of the node, defaults to `None`
    :type vars: dict

    :return: None on Success and Failure
    :rtype: None
    """
    try:
        from rmaker_tools.rmaker_prov.esp_rainmaker_prov\
             import provision_device
    except ImportError as err:
        import google.protobuf
        if version.parse(google.protobuf.__version__)\
                < version.parse(MINIMUM_PROTOBUF_VERSION):
            log.warn('Package protobuf does not satisfy\
                     the minimum required version.\n'
                     'Minimum required version is ' + MINIMUM_PROTOBUF_VERSION)
        else:
            log.error('Provisioning failed due to import error.', err)
            raise err
    log.info('Provisioning the node.')
    secret_key = str(uuid.uuid4())
    pop = vars['pop']
    try:
        config = configmanager.Config()
        userid = config.get_user_id()
        log.debug('User session is initialized for the user ' + userid)
    except Exception as get_user_id_err:
        log.error(get_user_id_err)
        sys.exit(1)
    try:
        input('Please connect to the wifi PROV_XXXXXX and '
              'Press Enter to continue...')
    except Exception:
        print("Exiting...")
        sys.exit(0)

    node_id = provision_device(TRANSPORT_MODE_SOFTAP, pop, userid, secret_key)
    if node_id is None:
        print(PROVISION_FAILURE_MSG)
        return
    log.debug('Node ' + node_id + ' provisioned successfully.')

    print('------------------------------------------')
    input('Please ensure host machine is connected to internet and'
          'Press Enter to continue...')
    print('Adding User-Node association...')
    retries = MAX_HTTP_CONNECTION_RETRIES
    node_object = None
    while retries > 0:
        try:
            # If session is expired then to initialise the new session
            # internet connection is required.
            node_object = node.Node(node_id, session.Session())
        except SSLError:
            log.error(SSLError())
            print(PROVISION_FAILURE_MSG)
            return
        except NetworkError:
            time.sleep(5)
            log.warn("Session is expired. Initialising new session.")
            pass
        except Exception as node_init_err:
            log.error(node_init_err)
            print(PROVISION_FAILURE_MSG)
            return
        else:
            break
        retries -= 1

    if node_object is None:
        print('Please check the internet connectivity.')
        print(PROVISION_FAILURE_MSG)
        return
    retries = MAX_HTTP_CONNECTION_RETRIES
    request_id = None
    while retries > 0:
        try:
            log.debug('Adding user-node association.')
            request_id = node_object.add_user_node_mapping(secret_key)
        except SSLError:
            log.error(SSLError())
            print(PROVISION_FAILURE_MSG)
            return
        except Exception as user_node_mapping_err:
            print('Sending User-Node association request to '
                  'ESP RainMaker Cloud - Failed\nRetrying...')
            log.warn(user_node_mapping_err)
            pass
        else:
            if request_id is not None:
                log.debug('User-node mapping added successfully'
                          'with request_id' + request_id)
                break
        time.sleep(5)
        retries -= 1

    if request_id is None:
        print('Sending User-Node association request to'
              'ESP RainMaker Cloud - Failed')
        print(PROVISION_FAILURE_MSG)
        return
    print('Sending User-Node association request to'
          'ESP RainMaker Cloud - Successful')

    status = None
    while True:
        log.debug('Checking user-node association status.')
        try:
            status = node_object.get_mapping_status(request_id)
        except SSLError:
            log.error(SSLError())
            print(PROVISION_FAILURE_MSG)
            return
        except Exception as mapping_status_err:
            log.warn(mapping_status_err)
            pass
        else:
            log.debug('User-node association status ' + status)
            if status == 'requested':
                print('Checking User Node association status -'
                      'Requested\nRetrying...')
            elif status == 'confirmed':
                print('Checking User Node association status - Confirmed')
                print('Provisioning was Successful.')
                return
            elif status == 'timedout':
                print('Checking User Node association status - Timeout')
                print(PROVISION_FAILURE_MSG)
                return
            elif status == 'discarded':
                print('Checking User Node association status - Discarded')
                print(PROVISION_FAILURE_MSG)
                return
        time.sleep(5)

    if status is None:
        print(PROVISION_FAILURE_MSG)
        print('Checking User Node association status failed. '
              'Please check the internet connectivity.')
        return
    return