Beispiel #1
0
    def get_element_by_id(element_id: int, platform_access: PlatformAccess,
                          board: 'Board') -> Optional['Element']:
        """
        Returns an Element by the given board and ID

        :param element_id: Element's ID to retrieve
        :param platform_access: PlatformAccess of a user with access rights
        :param board: Element's board

        :return: Element if found, otherwise None
        """
        # Compose the request, execute it, and retrieve its data
        http_method = 'GET'
        detail = 'elements'
        url = compose_path(platform_access.get_platform_url(), 'boards',
                           board.get_id(), 'elements', element_id)

        values = {}
        headers = platform_access.get_headers(http_method, url, values, detail)
        response = request(method=http_method, url=url, headers=headers)
        response.raise_for_status()
        response_data = response.json()

        href = response_data['element']['_links'][0]['href']
        name = response_data['element']['caption']

        element = Element(platform_access, name, href, board)
        return element
Beispiel #2
0
    def update_agent_task(self, form: Dict) -> None:
        """
        Upload an agent task to backend
        :param: form: an agent task to be uploaded
        :return None
        """
        if not form:
            return None
        agent_task = form.get('agentTask', None)
        if not agent_task:
            return None
        agent_task_id = agent_task.get('id', None)

        agent_name = form['filename'].split('/')[0].split('_service')[0]
        agent_data_id, credentials = self.get_agent_data_id_by_agent_name(agent_name)
        if not agent_data_id:
            print(f'Agent id of {agent_name} is not found')
            return None

        backend_agent_task = get_agent_task_by_id(PlatformAccess(credentials[0], credentials[1]),
                                                  agent_data_id=agent_data_id,
                                                  agent_task_id=agent_task_id)

        if not backend_agent_task:
            backend_agent_task = "Wasn't found"

        # Get confirmation to do the operation
        if not self._get_confirmation(f'Current configuration: \n {json.dumps(backend_agent_task, indent=2)}\n'
                                      f'New configuration: \n {json.dumps(agent_task, indent=2)}\n'
                                      f'Update AgentTask configuration on the back-end?.. [y/N]\n'):
            return None

        # Update task
        update_agent_task_by_id(PlatformAccess(credentials[0], credentials[1]), agent_data_id=agent_data_id, task_file_name=form[FILENAME_KEY], agent_task_id=agent_task_id)
Beispiel #3
0
    def _get_remote_agent_tasks(self) -> [Dict, None]:
        """
        Returns all the AgentTasks a user has access to
        :return: None or a dict where a key is an agent_data_id and a value is a list of tasks
        """
        agent_tasks = dict()

        local_configs = self._get_agents_configs_local()
        platform_access = PlatformAccess(LOGIN, PASSWORD)
        user_id = platform_access.get_user_id()

        # Execute GET-request to get AgentData
        response = make_request(platform_access=platform_access,
                                http_method='GET',
                                url_postfix='agentdata',
                                detail='agentsData')
        if not response:
            return None
        data = response.json()
        if 'agentsData' in data:
            for agent in data['agentsData']:
                if user_id != str(agent['agentsUser']['id']):
                    continue
                for config in local_configs.values():
                    agent_name = config['agentData']['name']
                    credentials = self.find_agent_credentials(agent_name)
                    if not credentials[0]:
                        continue

                    # Add AgentTasks to the dictionary
                    agent_tasks[f'{agent["id"]}'] = agent['agentTasks'], credentials, agent_name

        return agent_tasks
Beispiel #4
0
def get_agent_data_by_user_id(platform_access: PlatformAccess, user_id: int = None) -> Optional[Dict]:
    """
    Returns agent's data

    :param platform_access: User's PlatformAccess, generated with login/password tuple
    :param user_id: Not to confuse with AgentData ID!..

    :return: AgentData configuration if a request was successful, otherwise None
    """
    if not user_id:
        user_id = platform_access.get_user_id()
    try:
        http_method = 'GET'
        detail = 'agentData'
        postfix = f'user/{user_id}/agentdata'
        response = make_request(platform_access=platform_access,
                                http_method=http_method,
                                url_postfix=postfix,
                                detail=detail)
        response.raise_for_status()
    except (HTTPError, ConnectionError) as error:
        logger.error(OWN_ADAPTER_NAME, f'Error while updating database: {error}', response)
        return None
    else:
        logger.debug(OWN_ADAPTER_NAME, f'Successfully updated the database: {response}', response)
        if response:
            return response.json()
        return None
Beispiel #5
0
def put_agent_data(platform_access: PlatformAccess,
                   data: Union[Dict, str], agent_data_id: int) -> Optional[Dict]:
    """
    Updates the instance of AgentDataConfiguration on the back-end
    Reference: https://github.com/own-dev/own-agent-open/blob/master/docs/APIDescription.md#put-agentdataagentdataid

    :param platform_access: PlatformAccess for this Agent
    :param data: AgentData configuration in dictionary or JSON (str) format
    :param agent_data_id: ID of AgentData for the associated Agent on the back-end

    :return: Updated AgentData if request was successful, or None otherwise
    """
    http_method = 'PUT'
    detail = 'agentData'
    postfix = f'agentdata/{agent_data_id}'
    data['agentData']['agentsUserId'] = platform_access.get_user_id()
    if isinstance(data, str):
        data = json.loads(data)
    try:
        response = make_request(platform_access=platform_access,
                                http_method=http_method,
                                detail=detail,
                                url_postfix=postfix,
                                data=data)
        response.raise_for_status()
    except (HTTPError, ConnectionError) as excpt:
        logger.error(OWN_ADAPTER_NAME, f'Error while updating database: {excpt}', response)
        return None
    else:
        logger.debug(OWN_ADAPTER_NAME, f'Successfully updated the database: {response}', response)
        if response:
            return response.json()
        return None
Beispiel #6
0
    def _add_new_config(self, kwargs: Dict) -> None:
        """
        Adds new AgentData to the back-end from the given config_data and config_path;
        later then updates the local configs with newly assigned IDs
        :param kwargs: {'config_data': Dict, 'config_path': str}
                       config_path -- absolute path to the config to add
                       config_data -- settings.conf as a dictionary
        :return: Nothing
        """
        # Check if data exists
        config_data: Dict = kwargs.get('config_data', None)
        config_path: str = kwargs.get('config_path', None)
        if not (config_data and config_path):
            return

        # Get new credentials from env. vars
        agent_name = config_data['agentData']['name']
        if not agent_name:
            return
        credentials = self.find_agent_credentials(agent_name)

        # Execute POST-request
        response = post_agent_data(platform_access=PlatformAccess(credentials[0], credentials[1]), data=config_data)
        if not response:
            return

        # Update local machine's config
        self._json_to_config(json_data=json.dumps(response), conf_filepath=config_path)
Beispiel #7
0
def post_agent_data(platform_access: PlatformAccess, data: Dict) -> Optional[Dict]:
    """
    Creates new instance of  AgentDataConfiguration on the back-end

    :param platform_access:
    :param data: agentData-like dict TODO: Check if it is dict or str

    :return: New JSON-data (with IDs) if the request was successful, otherwise None
    """
    try:
        http_method = 'POST'
        detail = 'agentData'
        postfix = 'agentdata'
        data['agentData']['agentsUserId'] = platform_access.get_user_id()
        response = make_request(platform_access=platform_access,
                                http_method=http_method,
                                url_postfix=postfix,
                                detail=detail,
                                data=data)

        response.raise_for_status()
    except (HTTPError, ConnectionError) as excpt:
        logger.error(OWN_ADAPTER_NAME, f'Error while updating database: {excpt}', response)
    else:
        logger.debug(OWN_ADAPTER_NAME, f'Successfully updated the database: {response}', response)
        if response:
            return response.json()
        return None
Beispiel #8
0
    def refresh_configs_menu_create(self) -> None:
        """
        Refreshes AgentData::Create menu
        :return: None
        """
        local_configs = self._get_agents_configs_local()

        # Generate menu-items (options)
        new_options = list()
        for config_filepath, config in local_configs.items():
            agent_name = config['agentData']['name']
            credentials = self.find_agent_credentials(agent_name)
            if not (credentials[0] and credentials[1]):
                continue
            agent_data = get_agent_data_by_user_id(PlatformAccess(credentials[0], credentials[1]))
            if agent_data:
                continue

            # Create a new menu-item
            config_data = json.loads(self.config_to_json(config_filepath))
            new_options.append((f'{agent_name} agent',
                                self._add_new_config,
                                {'config_path': config_filepath, 'config_data': config_data}))

        new_options.append(BACK)

        # Set options for creation menu
        self.configs_menu_create.set_options(new_options)
Beispiel #9
0
    def find_local_agent_name_by_id(self, agent_data_id: int,
                                    local_configs: Dict = None) -> Tuple[str, Tuple[str, str], Dict]:
        """
        Find an agent name by id from local configs
        :param agent_data_id: an agent data id
        :param local_configs: a list containing local configs
        :return: the agent name, credentials and a local config of that agent
        """
        if not local_configs:
            local_configs = self._get_agents_configs_local()
        # Different agents should have different credentials
        for config_filepath, config in local_configs.items():
            # Read the config
            local_agent_name = config['agentData']['name']
            credentials = self.find_agent_credentials(local_agent_name)
            if not credentials[0]:
                continue
            agent_data = get_agent_data_by_user_id(PlatformAccess(credentials[0], credentials[1]))
            if not agent_data:
                continue
            if agent_data['agentData']['id'] == agent_data_id:
                config['file_path'] = config_filepath
                return local_agent_name, credentials, config

        return '', ('', ''), {}
Beispiel #10
0
    def _remove_agent_task(self, data: Dict) -> None:
        """
        Removes the AgentTask by the given AgentDataID and AgentTaskID
        :param data: {'data_id': int, 'credentials': Tuple[str, str], 'task_id': int}
                       data_id -- agent_data_id
                       credentials -- a login and a password of an agent of the task
                       task_id -- agent_task_id
                       agent_name -- a name of the agent name
        :return None
        """
        agent_data_id = data.get('data_id', None)
        agent_task_id = data.get('task_id', None)
        credentials = data.get('credentials', None)
        agent_name = data.get('agent_name', None)

        if not agent_task_id or not agent_data_id or not credentials:
            return

        # Get confirmation to do the operation
        if not self._get_confirmation():
            return

        # Execute DELETE-request
        response = remove_agent_task_by_id(platform_access=PlatformAccess(credentials[0], credentials[1]),
                                           agent_data_id=agent_data_id,
                                           agent_task_id=agent_task_id)
        if not response:
            return

        # TODO: Remove IDs for the local file, if it persist on the machine
        def remove_local_form_of_agent_task():
            """Removes AgentTask file from the local machine"""
            # Read the configs
            service_abs_path = os.path.join(self.services_abs_path, f'{agent_name}_service')

            agent_tasks_abs_path = os.path.join(service_abs_path, 'agent_tasks')
            for form in os.listdir(agent_tasks_abs_path):
                if not form.endswith('.json'):
                    continue

                # Read AgentTask
                form_abs_path = os.path.join(agent_tasks_abs_path, form)
                with open(form_abs_path, 'r') as file:
                    form_data: Dict = json.load(file).get('agentTask', None)

                # Check if it has ID
                current_form_id = form_data.get('id', None)
                if current_form_id and current_form_id == agent_task_id:
                    form_data.pop('id')
                    with open(form_abs_path, 'w') as file:
                        json.dump({'agentTask': form_data}, file, indent=2)
                    return

        remove_local_form_of_agent_task()
Beispiel #11
0
    def put_comment(self,
                    platform_access: PlatformAccess,
                    comment: str = '',
                    link: str = '') -> Optional[int]:
        """
        Puts a comment to file
        :param platform_access:
        :param comment: comment text
        :param link: url of link, where to put comment
        :return: response status or none
        """
        try:
            http_method = 'POST'
            detail = 'commentCreationResponse'
            url = link + '/comments'
            additional_headers = {
                'Content-Type': 'application/json; charset=UTF-8'
            }
            payload = json.dumps({'fileComment': {
                'message': comment
            }},
                                 separators=(',', ':'),
                                 ensure_ascii=False)
            values = {}

            headers = platform_access.get_headers(
                http_method,
                url,
                values,
                detail,
                payload=payload,
                additional_headers=additional_headers)
            response = requests.post(url=url,
                                     headers=headers,
                                     data=payload.encode())
            response_status = response.status_code
            response.raise_for_status()
            return response_status
        except requests.HTTPError as e:
            logger.exception(
                OWN_ADAPTER_NAME,
                f'Error: put comment {self._title} to {self.get_title()} failed. Error type: {e}',
                response)
            return None
        except Exception as e:
            logger.exception(
                OWN_ADAPTER_NAME,
                f'Error: put comment {self._title} to {self.get_title()} failed. Error type: {e}'
            )
            return None
Beispiel #12
0
    def refresh_configs_menu_update_or_remove(self, remove_flag: bool = False) -> None:
        """
        Refreshes either AgentDataConfigurations::Update or AgentDataConfigurations::Remove menu
        :param remove_flag: False - find configs to be updated, True - find configs to be removed
        :return: None
        """
        # Get the AgentData from the back-end
        local_configs = self._get_agents_configs_local()

        # To check if AgentData ID is unique; fool proof
        agent_data_ids = {}

        new_options = []
        for config_filepath, config in local_configs.items():
            local_agent_name = config['agentData']['name']
            credentials = self.find_agent_credentials(local_agent_name)
            if not (credentials[0] and credentials[1]):
                continue
            agent_data = get_agent_data_by_user_id(PlatformAccess(credentials[0], credentials[1]))
            if not agent_data:
                continue

            # Create a new menu-item
            if not remove_flag:
                # Create a new menu-item for Update
                new_options.append((local_agent_name, self._update_config,
                                    {'agent_data': agent_data,
                                     'agent_name': local_agent_name,
                                     'credentials': credentials,
                                     'config': config}))
            else:
                # Check if this AgentData ID is unique
                if agent_data['agentData']['id'] not in agent_data_ids:
                    # TODO: Log if it wasn't the unique ID
                    agent_data_ids[agent_data['agentData']['id']] = True

                    # Create a new menu-item for Remove
                    new_options.append((f'Id: {agent_data["agentData"]["id"]} :: Desc: '
                                        f'{agent_data["agentData"]["description"]}', self._remove_config,
                                        {'agent_data': agent_data, 'credentials': credentials}))

        new_options.append(BACK)

        # Add options to either menu
        if not remove_flag:
            self.configs_menu_update.set_options(new_options)
        else:
            self.configs_menu_remove.set_options(new_options)
Beispiel #13
0
    def get_agent_data_id_by_agent_name(self, agent_name: str) -> [Tuple[int, Tuple[str, str]],
                                                                   Tuple[None, Tuple[str, str]]]:
        """
        Get an agent data id from a config file of an agent
        :param agent_name: a name of the config file
        :return: the agent data id and credentials of the agent
        """

        credentials = self.find_agent_credentials(agent_name)
        if not credentials[0]:
            return None, credentials

        agent_data = get_agent_data_by_user_id(PlatformAccess(credentials[0], credentials[1]))
        if not agent_data:
            return None, credentials
        return agent_data['agentData']['id'], credentials
Beispiel #14
0
    def get_board_by_id(board_id: str,
                        platform_access: PlatformAccess,
                        need_name: bool = True) -> Optional['Board']:
        """
        Returns a board by its ID

        :param board_id: Board's ID on the platform/back-end
        :param platform_access: PlatformAccess object of a(n) user/agent
                                                which has access to this board?..
        :param need_name: Either to force-get (via request) board's name or not

        :return: Board instance for the given ID, or None if a board can't be created
        """
        name = ''
        if need_name:
            http_method = 'GET'
            detail = 'boards'
            url = f'{platform_access.get_platform_url()}/boards/{board_id}'
            values = {}
            headers = platform_access.get_headers(http_method, url, values,
                                                  detail)
            response = None
            try:
                response = request(method=http_method,
                                   url=url,
                                   headers=headers)
                response.raise_for_status()
            except HTTPError as http_error:
                logger.exception(
                    OWN_ADAPTER_NAME,
                    f'Could not perform name extraction: {http_error}',
                    response)
            except ConnectionError as connect_error:
                logger.exception(
                    OWN_ADAPTER_NAME,
                    f'Could not perform name extraction, connection-error: {connect_error}',
                    response)
            else:
                response_data = response.json()
                name = response_data['board']['name']

        # TODO: Check if the board exists?.. I.e., ID is correct, and the PlatformAccess-object can get it
        board = Board(platform_access, name, board_id)
        return board
Beispiel #15
0
    def __init__(self,
                 platform_access: PlatformAccess,
                 name: str = '',
                 identifier: str = '',
                 board: 'Board' = None,
                 pos_x: int = None,
                 pos_y: int = None,
                 size_x: int = None,
                 size_y: int = None,
                 last_processing_time: datetime = DEFAULT_PROCESSING_DATETIME,
                 agent_task_id: int = None,
                 agent_data_id: int = None):
        """
        :param platform_access: PlatformAccess of a user
                                who has access rights to it [board, i.e., boards]
        :param name: Element's caption
        :param identifier: Element's ID
        :param board: The board on which the element is on
        :param pos_x: Element's horizontal position, starting with 1
        :param pos_y: Element's vertical position, starting with 1
        :param size_x: Element's width
        :param size_y: Element's height
        :param last_processing_time: The last time this element was processed
        :param agent_task_id: AgentTask's ID that is assigned to the element (if some)
        :param agent_data_id: AgentData's ID of an agent that is assigned to the element
                              (if there is some)
        """
        self.__platform_access = platform_access
        self.__name = name
        if PREFIX and PREFIX in identifier:
            identifier = identifier[len(PREFIX) + 1:]
        self.__url = platform_access.get_platform_url() + identifier
        self.__id = identifier
        self.__board = board
        self.__last_processing_time = last_processing_time

        self.__pos_x = pos_x
        self.__pos_y = pos_y
        self.__size_x = size_x
        self.__size_y = size_y

        self.__agent_task_id = agent_task_id
        self.__agent_data_id = agent_data_id
Beispiel #16
0
    def __get_platform_access(self) -> [PlatformAccess, None]:
        """Returns PlatformAccess with valid agent's credentials (environ), None otherwise"""
        if not self.platform_access:
            try:
                login = os.environ[f'OWN_{self.name.upper()}_AGENT_LOGIN']
                password = os.environ[
                    f'OWN_{self.name.upper()}_AGENT_PASSWORD']
                self.platform_access = PlatformAccess(login, password)
            except KeyError as key_error:
                exception(
                    self.name,
                    f'Failed get credentials for {self.name}-agent. Error message: {str(key_error)}'
                )
            except Exception as err:
                error(
                    self.name,
                    f'Some error occurred while establishing connection to the platform: {err}'
                )

        return self.platform_access
Beispiel #17
0
    def _remove_config(self, dict_with_data: Dict) -> None:
        """
        Removes AgentData from the back-end
        :param dict_with_data: {'agent_data': Dict, 'credentials': Tuple[str, str]}
                       agent_data -- agent_data stored on the backend
                       credentials -- a login and a password of that agent
        :return: None
        """
        agent_data = dict_with_data['agent_data']['agentData']
        credentials = dict_with_data['credentials']
        agent_data_id = agent_data['id']

        backend_config_readable = self.config_to_readable(agent_data)
        if not self._get_confirmation(f'Agent config to be removed: \n {backend_config_readable}'
                                      f' \nAre you sure you want to '
                                      f'remove Agent with ID = {agent_data_id}? [y/N]'):
            return

        res = delete_agent_data(platform_access=PlatformAccess(credentials[0], credentials[1]),
                                agent_data_id=agent_data_id)
        if not res:
            print('Agent was not deleted')
Beispiel #18
0
    def _change_config_status(self, kwargs: Dict) -> None:
        """
        Changes config's status on the back-end
        :param kwargs: {'agent_name': str, 'new_status': str, 'agent_data': Dict}
                        agent_name -- a name of an agent
                        credentials -- a login and a password of that agent
                        agent_data -- agent data of the agent
        :return: Nothing
        """
        agent_name = kwargs.get('agent_name', None)
        new_status = kwargs.get('new_status', None)
        agent_data = kwargs.get('agent_data', None)

        if not (agent_name and new_status and agent_data):
            return

        agent_data_id = agent_data['id']
        # Fix the status to its real value
        # Input parameter can be 1, or 2, or 3
        # to escape "if not new_status:" when it's 0 (and not None)
        new_status -= 1

        agent_name, credentials, config = self.find_local_agent_name_by_id(agent_data_id)
        if not agent_name:
            print(f'You don\'t have access to that agent')
            return
        # Firstly, get confirmation to do te operation
        if not self._get_confirmation():
            return

        agent_data['status'] = new_status
        # Update the back-end
        response = put_agent_data(platform_access=PlatformAccess(credentials[0], credentials[1]),
                                  data={'agentData': agent_data}, agent_data_id=agent_data_id)
        if response:
            print(f'{agent_name}\'s status was set to {STATUS[str(new_status)]}.')
        else:
            print(f'{agent_name}\'s status was not updated.')
Beispiel #19
0
    def refresh_configs_menu_list(self) -> None:
        """
        Lists all the agent-services on the local machine
        Allows to Run or Stop them
        :return: Nothing
        """
        # Get AgentData configs from the back-end
        agent_datas = get_all_agents_data(PlatformAccess(LOGIN, PASSWORD))

        # Generate all the menu-items
        menu_items = list()
        for agent in agent_datas:
            # Create a new menu-item
            agent_name = f"{agent['agentsUser']['firstName']}"
            new_entry_name = f"{agent_name:<16} (id={agent['id']:<4})\t{agent['status']}"
            backend_config_readable = self.config_to_readable(agent)
            if 'agentTasks' in backend_config_readable:
                backend_config_readable.pop('agentTasks', None)
            new_entry = Menu(title=new_entry_name,
                             options=[
                                 ('Set ACTIVE', self._change_config_status,
                                  {'agent_name': agent_name.lower(), 'agent_data': agent, 'new_status': 1}),
                                 ('Set BEING_TESTED', self._change_config_status,
                                  {'agent_name': agent_name.lower(), 'agent_data': agent, 'new_status': 2}),
                                 ('Set INACTIVE', self._change_config_status,
                                  {'agent_name': agent_name.lower(), 'agent_data': agent, 'new_status': 3}),
                                 (f'AGENT CONFIG: \n{json.dumps(backend_config_readable, indent=2)}',
                                  lambda: None, None),
                                 BACK
                             ])
            menu_items.append(new_entry)

        # Generate options for AgentTasks::List
        new_options = [(config_item.title, config_item.open, None) for config_item in menu_items]
        new_options.append(BACK)

        self.configs_menu_list.set_options(new_options)
Beispiel #20
0
    def _create_new_agent_task(self, task_filepath: str) -> None:
        """
        Creates a new AgentTask on the back-end
        
        :param task_filepath: a path to a file with a task
        :return: None
        """
        # Check if data persists
        if not task_filepath:
            return

        # Get confirmation to do the operation
        if not self._get_confirmation():
            return

        agent_name = task_filepath.split('/')[0].split('_service')[0]

        agent_data_id, credentials = self.get_agent_data_id_by_agent_name(agent_name)
        if not agent_data_id:
            print(f'Agent id of {agent_name} is not found')
            return
        # Execute POST-request
        upload_or_update_agent_task_from_file(platform_access=PlatformAccess(credentials[0], credentials[1]),
                                              agent_data_id=agent_data_id, file_name=task_filepath, force_update=True)
Beispiel #21
0
def make_request(platform_access: PlatformAccess,
                 http_method: str,
                 url_postfix: Optional[str],
                 detail: str,
                 data: Dict = None,
                 values: Dict = None,
                 logger_name: str = None) -> Optional[Response]:
    """
    Makes request according the given parameters

    :param platform_access:
    :param http_method: {GET|POST|PUT|DELETE}
    :param url_postfix:
    :param detail:
    :param data: Actual payload
    :param values: # TODO: Check PlatformAccess::get_headers()
    :param logger_name: Name for logging, default is OWN_ADAPTER_NAME
    :return: requests.Response
    """
    # Set default values
    if values is None:
        values = dict()
    if not logger_name:
        logger_name = OWN_ADAPTER_NAME

    try:
        # Generate the payload
        payload = json.dumps(
            data, separators=(',', ':'), sort_keys=True,
            ensure_ascii=False).encode('utf-8') if data else ''

        # Generate URL
        url = f'{platform_access.get_platform_url()}'
        if url_postfix:
            url += f'/{url_postfix}'

        debug(logger_name, f'URL: ({http_method}) {url}')

        # Generate headers
        if http_method != 'DELETE':
            headers = platform_access.get_headers(method=http_method,
                                                  url=url,
                                                  values=values,
                                                  detail=detail,
                                                  payload=payload,
                                                  additional_headers={})
        else:
            headers = platform_access.get_headers(method=http_method,
                                                  url=url,
                                                  values=values,
                                                  detail=detail)
    except ConnectionError as con_error:
        errno, strerror = con_error.args
        exception(logger_name, f'Connection error ({errno}): {strerror}')
        return None
    except Exception:
        exception(
            logger_name,
            f'Unexpected error while getting headers: {sys.exc_info()[0]}')
        return None
    else:
        debug(logger_name, f'Successfully generated headers:\n{headers}')

    try:
        # Make a request
        if http_method != 'DELETE':
            response = request(url=url,
                               method=http_method,
                               headers=headers,
                               data=payload)
        else:
            response = request(url=url, method=http_method, headers=headers)

    except HTTPError as http_error:
        exception(
            logger_name,
            f'HTTP error ({http_error.errno}) while making request: {http_error}'
        )
        return None
    except ConnectionError as con_error:
        exception(
            logger_name,
            f'HTTP error ({con_error.errno}) while making request: {con_error}'
        )
        return None
    except URLError as url_error:
        exception(logger_name,
                  f'URL error, failed to reach server: {url_error.reason}')
        return None
    else:
        debug(
            logger_name,
            f'Successfully made a request, code {response.status_code}, {response}'
        )
        return response
Beispiel #22
0
    def _update_config(self, data: Dict) -> None:
        """
        Updates AgentData on the back-end
        :param data: {'agent_data': Dict, 'agent_name': str, 'credentials': Tuple[str, str], 'config': Dict}
                       agent_data -- agent_data stored on the backend
                       agent_name -- a name of an agent to be updated
                       credentials -- a login and a password of that agent
                       config -- a local config to be uploaded
                       
        :return: None
        """
        backend_config = data['agent_data']['agentData']
        agent_name = data['agent_name']
        credentials = data['credentials']
        data = data['config']
        local_config_data = data['agentData']

        # Update the local config with IDs from the back-end
        new_config_data_with_ids = local_config_data
        new_config_data_with_ids[ID_KEY] = backend_config[ID_KEY]

        def find_subs_plan_by_period_name(subscription_plans: List[Dict], period_val: PeriodicalPlan) -> Optional[Dict]:
            """
            Searches for the needed subscription plan in the given ones by name
            Reference: See Agent Data section in docs/APIDescription.md
            :param subscription_plans: Subscription plans to search in
            :param period_val: "DAY", "WEEK", or "MONTH"
            :return: If found, returns a subscription plan data for the given period, otherwise, None
            """
            if not (subscription_plans and period_val):
                return None

            required_subscription_plan = None
            for plan in subscription_plans:
                if plan[SUBSCRIPTION_INTERVAL_KEY] == period_val:
                    required_subscription_plan = plan
                    break
            return required_subscription_plan

        # Adds IDs for the new config parsed from the one form back-end
        # TODO: After production server's updated for Organization payments, add its handling
        backend_subscriptions = backend_config[SUBSCRIPTION_PLANS_KEY]
        for idx, period in enumerate(PERIODS):
            back_subs_plan = find_subs_plan_by_period_name(backend_subscriptions, period)
            if not back_subs_plan:
                continue

            # Update subscription interval ID
            back_interval_id = back_subs_plan[ID_KEY]
            new_config_data_with_ids[SUBSCRIPTION_PLANS_KEY][idx][ID_KEY] = \
                back_interval_id

            # Update subscription plan pricing ID
            back_plan_pricing_id = back_subs_plan[PLAN_PRICINGS_KEY][0][ID_KEY]  # For euro-currency
            new_config_data_with_ids[SUBSCRIPTION_PLANS_KEY][idx][PLAN_PRICINGS_KEY][0][ID_KEY] = \
                back_plan_pricing_id

        # Get confirmation to do the operation
        backend_config_readable = self.config_to_readable(backend_config)
        old_config = json.dumps(backend_config_readable, indent=2)
        new_config = json.dumps(local_config_data, indent=2)
        
        if not self._get_confirmation(f'Current configuration: \n {old_config}\n'
                                      f'New configuration: \n {new_config}\n'
                                      f'Update {agent_name}\'s configuration on the back-end?.. [y/N]\n'):
            return

        # Actually update it
        res = put_agent_data(platform_access=PlatformAccess(credentials[0], credentials[1]),
                             data=data, agent_data_id=backend_config['id'])
        if not res:
            print('Agent was not updated')