예제 #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 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
예제 #3
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'])
    if 'data' in vars:
        data = vars['data']
    if 'filepath' in vars:
        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 SSLError:
        log.error(SSLError())
    except NetworkError as conn_err:
        print(conn_err)
        log.warn(conn_err)
    except Exception as set_params_err:
        log.error(set_params_err)
    else:
        print('Node state updated successfully.')
    return
예제 #4
0
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)
예제 #5
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
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