Ejemplo n.º 1
0
    def get_by_template(req, template_id):
        """
        Return a list of devices that have a particular template associated to
        it

        :param req: The received HTTP request, as created by Flask.
        :param template_id: The template to be considered
        :raises HTTPRequestError: If no authorization token was provided (no
        tenant was informed)
        :raises HTTPRequestError: If this device or template could not be found
        in database.
        :return A list of devices that are associated to the selected template.
        :rtype JSON
        """
        tenant = init_tenant_context(req, db)

        page_number, per_page = get_pagination(req)
        page = (db.session.query(Device).join(DeviceTemplateMap).filter_by(
            template_id=template_id).paginate(page=page_number,
                                              per_page=per_page,
                                              error_out=False))
        devices = []
        for d in page.items:
            devices.append(serialize_full_device(d, tenant))

        result = {
            'pagination': {
                'page': page.page,
                'total': page.pages,
                'has_next': page.has_next,
                'next_page': page.next_num
            },
            'devices': devices
        }
        return result
Ejemplo n.º 2
0
def flask_get_templates():
    try:
        # retrieve the authorization token
        token = retrieve_auth_token(request)

        # retrieve pagination
        page_number, per_page = get_pagination(request)

        params = {
            'page_number': page_number,
            'per_page': per_page,
            'sortBy': request.args.get('sortBy', None),
            'attr': request.args.getlist('attr'),
            'attr_type': request.args.getlist('attr_type'),
            'label': request.args.get('label', None),
            'attrs_format': request.args.get('attr_format', 'both')
        }

        result = TemplateHandler.get_templates(params, token)

        for templates in result.get('templates'):
            LOGGER.info(f" Getting template with id {templates.get('id')}")

        return make_response(jsonify(result), 200)

    except ValidationError as e:
        results = {'message': 'failed to parse attr', 'errors': e}
        LOGGER.error(f" {e}")
        return make_response(jsonify(results), 500)

    except HTTPRequestError as e:
        LOGGER.error(f" {e}")
        if isinstance(e.message, dict):
            return make_response(jsonify(e.message), e.error_code)
        return format_response(e.error_code, e.message)
Ejemplo n.º 3
0
    def get_templates(req):
        """
        Fetches known templates, potentially limited by a given value. Ordering
        might be user-configurable too.

        :param req: The received HTTP request, as created by Flask.
        :return A JSON containing pagination information and the template list
        :rtype JSON
        :raises HTTPRequestError: If no authorization token was provided (no
        tenant was informed)
        """
        init_tenant_context(req, db)

        page_number, per_page = get_pagination(req)
        pagination = {'page': page_number, 'per_page': per_page, 'error_out': False}

        parsed_query = []
        query = req.args.getlist('attr')
        for attr in query:
            parsed = re.search('^(.+){1}=(.+){1}$', attr)
            parsed_query.append(text("attrs.label = '{}'".format(parsed.group(1))))
            parsed_query.append(text("attrs.static_value = '{}'".format(parsed.group(2))))

        target_label = req.args.get('label', None)
        if target_label:
            parsed_query.append(text("templates.label like '%{}%'".format(target_label)))

        SORT_CRITERION = {
            'label': DeviceTemplate.label,
            None: DeviceTemplate.id
        }
        sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), DeviceTemplate.id)

        if parsed_query:
            LOGGER.debug(f" Filtering template by {parsed_query}")
            page = db.session.query(DeviceTemplate) \
                             .join(DeviceAttr, isouter=True) \
                             .filter(*parsed_query) \
                             .order_by(sortBy) \
                             .paginate(**pagination)
        else:
            LOGGER.debug(f" Querying templates sorted by {sortBy}")
            page = db.session.query(DeviceTemplate).order_by(sortBy).paginate(**pagination)

        templates = []
        for template in page.items:
            templates.append(attr_format(req, template_schema.dump(template)))

        result = {
            'pagination': {
                'page': page.page,
                'total': page.pages,
                'has_next': page.has_next,
                'next_page': page.next_num
            },
            'templates': templates
        }

        return result
Ejemplo n.º 4
0
    def test_get_pagination(self):

        args = {'page_size': 10,'page_num': 1}
        req = {'headers': {'authorization': generate_token()},'args': args,'body': ''}

        page, per_page = get_pagination(Request(req))
        self.assertEqual(page, 1)
        self.assertEqual(per_page, 10)

        with self.assertRaises(HTTPRequestError):
            args = {'page_size': 10,'page_num': 0}
            req = {'headers': {'authorization': generate_token()},'args': args,'body': ''}
            page, per_page = get_pagination(Request(req))

        with self.assertRaises(HTTPRequestError):
            args = {'page_size': 0,'page_num': 2}
            req = {'headers': {'authorization': generate_token()},'args': args,'body': ''}
            page, per_page = get_pagination(Request(req))
Ejemplo n.º 5
0
def flask_get_by_template(template_id):
    try:
        # retrieve the authorization token
        token = retrieve_auth_token(request)

        # retrieve pagination
        page_number, per_page = get_pagination(request)

        params = {
            'page_number': page_number,
            'per_page': per_page,
        }

        LOGGER.info(f' Getting devices with template id {template_id}.')
        result = DeviceHandler.get_by_template(token, params, template_id)
        return make_response(jsonify(result), 200)
    except HTTPRequestError as e:
        LOGGER.error(f' {e.message} - {e.error_code}.')
        if isinstance(e.message, dict):
            return make_response(jsonify(e.message), e.error_code)

        return format_response(e.error_code, e.message)
Ejemplo n.º 6
0
def flask_get_devices():
    """
    Fetches known devices, potentially limited by a given value. Ordering might
    be user-configurable too.

    Check API description for more information about request parameters and
    headers.
    """
    try:
        # retrieve the authorization token
        token = retrieve_auth_token(request)

        # retrieve pagination
        page_number, per_page = get_pagination(request)

        params = {
            'page_number': page_number,
            'per_page': per_page,
            'sortBy': request.args.get('sortBy', None),
            'attr': request.args.getlist('attr'),
            'attr_type': request.args.getlist('attr_type'),
            'label': request.args.get('label', None),
            'template': request.args.get('template', None),
            'idsOnly': request.args.get('idsOnly', 'false'),
        }

        result = DeviceHandler.get_devices(token, params)
        LOGGER.info(f' Getting latest added device(s).')

        return make_response(jsonify(result), 200)
    except HTTPRequestError as e:
        LOGGER.error(f' {e.message} - {e.error_code}.')
        if isinstance(e.message, dict):
            return make_response(jsonify(e.message), e.error_code)

        return format_response(e.error_code, e.message)
Ejemplo n.º 7
0
    def get_templates(req):
        """
        Fetches known templates, potentially limited by a given value. Ordering
        might be user-configurable too.

        :param req: The received HTTP request, as created by Flask.
        :return A JSON containing pagination information and the template list
        :rtype JSON
        :raises HTTPRequestError: If no authorization token was provided (no
        tenant was informed)
        """
        LOGGER.debug(f"Retrieving templates.")
        LOGGER.debug(f"Initializing tenant context...")
        init_tenant_context(req, db)
        LOGGER.debug(f"... tenant context initialized.")

        page_number, per_page = get_pagination(req)
        pagination = {
            'page': page_number,
            'per_page': per_page,
            'error_out': False
        }

        LOGGER.debug(f"Pagination configuration is {pagination}")

        parsed_query = []
        query = req.args.getlist('attr')
        for attr in query:
            LOGGER.debug(f"Analyzing query parameter: {attr}...")
            parsed = re.search('^(.+){1}=(.+){1}$', attr)
            parsed_query.append(DeviceAttr.label == parsed.group(1))
            parsed_query.append(DeviceAttr.static_value == parsed.group(2))
            LOGGER.debug("... query parameter was added to filter list.")

        query = req.args.getlist('attr_type')
        for attr_type_item in query:
            parsed_query.append(DeviceAttr.value_type == attr_type_item)

        target_label = req.args.get('label', None)
        if target_label:
            LOGGER.debug(f"Adding label filter to query...")
            parsed_query.append(
                DeviceTemplate.label.like("%{}%".format(target_label)))
            LOGGER.debug(f"... filter was added to query.")

        SORT_CRITERION = {'label': DeviceTemplate.label, None: None}
        sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), None)
        LOGGER.debug(f"Sortby filter is {sortBy}")
        if parsed_query:
            LOGGER.debug(f" Filtering template by {parsed_query}")

            # Always sort by DeviceTemplate.id
            page = db.session.query(DeviceTemplate) \
                             .join(DeviceAttr, isouter=True) \
                             .filter(*parsed_query) \
                             .order_by(DeviceTemplate.id)
            if sortBy:
                page = page.order_by(sortBy)

            page = page.distinct(DeviceTemplate.id)

            LOGGER.debug(f"Current query: {type(page)}")
            page = paginate(page, **pagination)
        else:
            LOGGER.debug(f" Querying templates sorted by {sortBy}")
            page = db.session.query(DeviceTemplate).order_by(sortBy).paginate(
                **pagination)

        templates = []
        for template in page.items:
            formatted_template = attr_format(req,
                                             template_schema.dump(template))
            LOGGER.debug(f"Adding resulting template to response...")
            LOGGER.debug(f"Template is: {formatted_template['label']}")
            templates.append(formatted_template)
            LOGGER.debug(f"... template was added to response.")

        result = {
            'pagination': {
                'page': page.page,
                'total': page.pages,
                'has_next': page.has_next,
                'next_page': page.next_num
            },
            'templates': templates
        }

        LOGGER.debug(f"Full response is {result}")

        return result
Ejemplo n.º 8
0
    def get_devices(req, sensitive_data=False):
        """
        Fetches known devices, potentially limited by a given value. Ordering
        might be user-configurable too.

        :param req: The received HTTP request, as created by Flask.
        :param sensitive_data: Informs if sensitive data like keys should be
        returned
        :return A JSON containing pagination information and the device list
        :rtype JSON
        :raises HTTPRequestError: If no authorization token was provided (no
        tenant was informed)
        """

        if req.args.get('idsOnly', 'false').lower() in ['true', '1', '']:
            return DeviceHandler.list_ids(req)

        tenant = init_tenant_context(req, db)

        page_number, per_page = get_pagination(req)
        pagination = {'page': page_number, 'per_page': per_page, 'error_out': False}

        SORT_CRITERION = {
            'label': Device.label,
            None: Device.id
        }
        sortBy = SORT_CRITERION.get(req.args.get('sortBy', None), Device.id)

        attr_filter = []
        query = req.args.getlist('attr')
        for attr in query:
            parsed = re.search('^(.+){1}=(.+){1}$', attr)
            attr = []
            attr.append("attrs.label = '{}'".format(parsed.group(1)))
            # static value must be the override, if any
            attr.append("coalesce(overrides.static_value, attrs.static_value) = '{}'".format(parsed.group(2)))
            attr_filter.append(and_(*attr))

        label_filter = []
        target_label = req.args.get('label', None)
        if target_label:
            label_filter.append("devices.label like '%{}%'".format(target_label))
        
        template_filter = []
        target_template = req.args.get('template', None)
        if target_template:
            template_filter.append("device_template.template_id = {}".format(target_template))
        
        if template_filter or label_filter or attr_filter:
            # find all devices that contain matching attributes (may contain devices that
            # do not match all required attributes)
            subquery = db.session.query(func.count(Device.id).label('count'), Device.id) \
                                 .join(DeviceTemplateMap, isouter=True) \
                                 .join(DeviceTemplate) \
                                 .join(DeviceAttr, isouter=True) \
                                 .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True) \
                                 .filter(or_(*attr_filter)) \
                                 .filter(*label_filter) \
                                 .filter(*template_filter) \
                                 .group_by(Device.id) \
                                 .subquery()
            # devices must match all supplied filters
            if (len(attr_filter)):
                LOGGER.debug(f" Filtering devices by {attr_filter}")
                page = db.session.query(Device) \
                             .join(DeviceTemplateMap) \
                             .join(subquery, subquery.c.id == Device.id) \
                             .filter(subquery.c.count == len(attr_filter)) \
                             .filter(*label_filter) \
                             .filter(*template_filter) \
                             .order_by(sortBy) \
                             .paginate(**pagination)
            else: # only filter by label
                LOGGER.debug(f" Filtering devices by label")
                page = db.session.query(Device) \
                        .join(DeviceTemplateMap) \
                        .join(subquery, subquery.c.id == Device.id) \
                        .filter(*label_filter) \
                        .filter(*template_filter) \
                        .order_by(sortBy) \
                        .paginate(**pagination)
        else:
            LOGGER.debug(f" Querying devices sorted by {sortBy}")
            page = db.session.query(Device).order_by(sortBy).paginate(**pagination)

        status_info = StatusMonitor.get_status(tenant)

        devices = []
        for d in page.items:
            devices.append(serialize_full_device(d, tenant, sensitive_data, status_info))

        result = {
            'pagination': {
                'page': page.page,
                'total': page.pages,
                'has_next': page.has_next,
                'next_page': page.next_num
            },
            'devices': devices
        }
        return result
Ejemplo n.º 9
0
    def get_devices(req, sensitive_data=False):
        """
        Fetches known devices, potentially limited by a given value. Ordering
        might be user-configurable too.

        :param req: The received HTTP request, as created by Flask.
        :param sensitive_data: Informs if sensitive data like keys should be
        returned
        :return A JSON containing pagination information and the device list
        :rtype JSON
        :raises HTTPRequestError: If no authorization token was provided (no
        tenant was informed)
        """

        tenant = init_tenant_context(req, db)

        page_number, per_page = get_pagination(req)
        pagination = {
            'page': page_number,
            'per_page': per_page,
            'error_out': False
        }

        SORT_CRITERION = {'label': Device.label, None: Device.id}
        sortBy = SORT_CRITERION.get(req.args.get('sortBy', None))

        attr_filter = []
        query = req.args.getlist('attr')
        for attr_label_item in query:
            parsed = re.search('^(.+){1}=(.+){1}$', attr_label_item)
            attr_label = []
            attr_label.append(DeviceAttr.label == parsed.group(1))
            # static value must be the override, if any
            attr_label.append(
                text(
                    "coalesce(overrides.static_value, attrs.static_value)=:static_value "
                ).bindparams(static_value=parsed.group(2)))
            attr_filter.append(and_(*attr_label))

        query = req.args.getlist('attr_type')
        for attr_type_item in query:
            attr_filter.append(DeviceAttr.value_type == attr_type_item)

        label_filter = []
        target_label = req.args.get('label', None)
        if target_label:
            label_filter.append(Device.label.like("%{}%".format(target_label)))

        template_filter = []
        target_template = req.args.get('template', None)
        if target_template:
            template_filter.append(
                DeviceTemplateMap.template_id == target_template)

        if (attr_filter):  #filter by attr
            LOGGER.debug(f" Filtering devices by {attr_filter}")

            page = db.session.query(Device) \
                            .join(DeviceTemplateMap, isouter=True)

            page = page.join(DeviceTemplate) \
                    .join(DeviceAttr, isouter=True) \
                    .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True)

            page = page.filter(*label_filter) \
                    .filter(*template_filter) \
                    .filter(*attr_filter) \
                    .order_by(sortBy) \
                    .paginate(**pagination)

        elif label_filter or template_filter:  # only filter by label or/and template
            if label_filter:
                LOGGER.debug(f"Filtering devices by label: {target_label}")

            if template_filter:
                LOGGER.debug(
                    f"Filtering devices with template: {target_template}")

            page = db.session.query(Device) \
                            .join(DeviceTemplateMap, isouter=True)

            if sensitive_data:  #aditional joins for sensitive data
                page = page.join(DeviceTemplate) \
                        .join(DeviceAttr, isouter=True) \
                        .join(DeviceOverride, (Device.id == DeviceOverride.did) & (DeviceAttr.id == DeviceOverride.aid), isouter=True)

            page = page.filter(*label_filter) \
                    .filter(*template_filter) \
                    .order_by(sortBy) \
                    .paginate(**pagination)

        else:
            LOGGER.debug(f" Querying devices sorted by device id")
            page = db.session.query(Device).order_by(sortBy).paginate(
                **pagination)

        devices = []

        if req.args.get('idsOnly', 'false').lower() in ['true', '1', '']:
            return DeviceHandler.get_only_ids(page)

        for d in page.items:
            devices.append(serialize_full_device(d, tenant, sensitive_data))

        result = {
            'pagination': {
                'page': page.page,
                'total': page.pages,
                'has_next': page.has_next,
                'next_page': page.next_num
            },
            'devices': devices
        }
        return result