def __init__(self, packets_obj=None, name=None, path=None):
        """Initialize a data source for reports to run against.

        :param packets_obj: Clip or File or Job object
        :param str name: Name of general report sources
        :param str path: Path of the packets data source
        """

        if not packets_obj and not name:
            raise AppResponseException("Either packets_obj or name is "
                                       "required to be a valid data source.")
        if packets_obj:
            if isinstance(packets_obj, Clip):
                path = '{}{}'.format(self.CLIP_PREFIX, packets_obj.id)
            elif isinstance(packets_obj, File):
                path = '{}{}'.format(self.FILE_PREFIX, packets_obj.id)
            elif isinstance(packets_obj, Job):
                path = '{}{}'.format(self.JOB_PREFIX, packets_obj.id)
            else:
                raise AppResponseException(
                    'Can only support job or clip or file packet source')

            self.name = 'packets'
            self.path = path
        else:
            self.name = name
            self.path = path
    def create_instance(self, data_defs):
        """Create a report instance with multiple data definition requests.

        :param data_defs: list of DataDef objects
        :return: one ReportInstance object
        """
        if not data_defs:
            msg = 'No data definitions are provided.'
            raise AppResponseException(msg)

        if (any(dd.source.name == 'packets' for dd in data_defs)
                and any(dd.source.name != 'packets' for dd in data_defs)):
            # Two report instance needs to be created, one uses 'npm.reports'
            # service, the other one uses 'npm.probe.reports' service
            # it would create unnecessary complexity to support this case
            # thus report error and let the user to create two separate
            # report instances

            msg = ('Both packets data source and non-packets data source are '
                   'being queried in this report, which is not supported. The '
                   'data source names include {}'.format(', '.join(
                       set([dd.source.name for dd in data_defs]))))
            raise AppResponseException(msg)

        def _create_and_run(service_name, data_defs):

            config = dict(data_defs=[dd.to_dict() for dd in data_defs])
            logger.debug("Creating instance with data definitions %s" % config)

            svcdef = self.appresponse.find_service(service_name)
            datarep = svcdef.bind('instances')
            resp = datarep.execute('create', _data=config)

            instance = ReportInstance(data=resp.data, datarep=resp)
            while not instance.is_complete():
                time.sleep(1)

            if instance.errors:
                err_msgs = ';\n'.join(instance.errors)
                raise AppResponseException(err_msgs)

            return instance

        if data_defs[0].source.name == 'packets':
            # Needs to create a clip for for capture job packets source
            # Keep the clip till the instance is completed
            with self.appresponse.clips.create_clips(data_defs):
                # capture job data_defs are modified in place
                instance = _create_and_run(PACKETS_REPORT_SERVICE_NAME,
                                           data_defs)
        else:
            instance = _create_and_run(GENERAL_REPORT_SERVICE_NAME, data_defs)
        return instance
Пример #3
0
    def create_clips(self, data_defs):
        """Create a Clips object from a list of data definition requests.
        When some DataDef objects are using sources other than capture jobs,
        then those sources will stay the same. The capture job sources will
        be converted into Clip objects.

        :param data_defs: list of DataDef objects
        :return: a Clips object
        """
        clips = []
        for dd in data_defs:
            if isinstance(dd.source, Job):
                logger.debug("Creating a Clip object for one data def request "
                             "with capture job '{}'"
                             .format(dd.source.name))

                clip = self.create_clip(dd.source, dd.timefilter,
                                        from_job=True)
                if clip.data.status.packets_written == 0:
                    msg = ('No packets found for job {} and {}'
                           .format(dd.source.name, dd.timefilter))
                    raise AppResponseException(msg)

                clips.append(clip)
            else:
                clips.append(dd.source)

        return Clips(clips)
Пример #4
0
 def get_job_by_id(self, id_):
     try:
         logger.debug("Obtaining Job object with id '{}'".format(id_))
         return next((j for j in self.get_jobs() if j.id == id_))
     except StopIteration:
         raise AppResponseException(
             "No capture job found with ID '{}'".format(id_))
Пример #5
0
    def get_job_by_name(self, name):

        try:
            logger.debug("Obtaining Job object with name '{}'".format(name))
            return next((j for j in self.get_jobs() if j.name == name))
        except StopIteration:
            raise AppResponseException(
                "No capture job found with name '{}'".format(name))
Пример #6
0
    def analyze(self, jobs):
        # Based on input pivot column names, i.e. CIFS, RTP, Facebook
        # using dataframe keyed by Application ID, and start time
        # derive dataframe keyed by start_time, with each row as
        # a dictionary keyed by input pivot values

        df = jobs['base'].data()
        # First clear all the dynamic columns that were associated with
        # the table last time the report is run
        # do not delete the time column
        for col in self.table.get_columns():
            if col.name == 'time':
                continue
            col.delete()

        base_table = Table.from_ref(self.table.options.tables.base)

        time_col_name = None
        for col in base_table.get_columns():
            if col.datatype == Column.DATATYPE_TIME and col.iskey:
                time_col_name = col.name
                break

        if not time_col_name:
            raise AppResponseException("No key 'time' column defined "
                                       "in base table")

        pivot_column = self.table.options.pivot_column_name

        sub_dfs = []
        for pivot in self.job.criteria.pivot_column_names.split(','):
            # Add pivot column to the table
            pivot = pivot.strip()
            AppResponseColumn.create(self.table, pivot, pivot)

            # Add pivot column to the data frame
            sub_df = df[df[pivot_column] == pivot]

            # extract time column and value column
            sub_df = sub_df[[
                time_col_name, self.table.options.value_column_name
            ]]
            # Rename columns to 'time' and the pivot column name
            sub_df.rename(columns={
                time_col_name: u'time',
                self.table.options.value_column_name: pivot
            },
                          inplace=True)

            sub_dfs.append(sub_df)

        df_final = reduce(
            lambda df1, df2: pandas.merge(df1, df2, on=u'time', how='outer'),
            sub_dfs)

        return QueryComplete(df_final)
Пример #7
0
    def check_for_errors(self):
        """Raise exception if any errors found."""
        # Check errors when all queries have completed
        for item in self.status:
            if item['state'] == 'error':
                for m in item['messages']:
                    self.errors.append(m['text'])
                    logger.error("Error msg from status: {}".format(m['text']))

        if self.errors:
            err_msgs = ';\n'.join(self.errors)
            raise AppResponseException(err_msgs)
        def _create_and_run(service_name, data_defs):

            config = dict(data_defs=[dd.to_dict() for dd in data_defs])
            logger.debug("Creating instance with data definitions %s" % config)

            svcdef = self.appresponse.find_service(service_name)
            datarep = svcdef.bind('instances')
            resp = datarep.execute('create', _data=config)

            instance = ReportInstance(data=resp.data, datarep=resp)
            while not instance.is_complete():
                time.sleep(1)

            if instance.errors:
                err_msgs = ';\n'.join(instance.errors)
                raise AppResponseException(err_msgs)

            return instance
Пример #9
0
    def get_data(self, index=0):
        """Return data for the indexed data definition requests.

        Note for live data objects `index` cannot be None, only
        explicit requests are allowed.  If multiple data_defs
        in a report need to collect data, query them individually.

        Also, the object returned from a live query will be a
        `data_def_results` object
        (https://support.riverbed.com/apis/npm.probe.reports/1.0/service.html#types_data_def_results)
        The data can be referenced via data['data'] but meta data
        about the results including endtime and startime can be
        found at data['meta']

        :param int index: Set to None to return data from all data
            definitions, defaults to returning the data from just
            the first data def.
        """
        if not self._instance.live:
            # get the already retrieved data
            if index is None:
                return [dd.data for dd in self._data_defs]
            return self._data_defs[index].data

        else:
            # need to do some special processing
            # first check for existing meta data, otherwise
            # do our first collection
            if index is None:
                msg = 'index must be a value for live reports'
                raise AppResponseException(msg)
            else:
                resp = self._instance.get_datadef_data(index)
                if not self._data_defs[index]._data_columns:
                    self._data_defs[index]._data_columns = resp['columns']

                source_name = self._data_defs[index].source.name
                if 'data' in resp:
                    data = self._cast_number(resp, source_name)
                else:
                    data = None
                return {'data': data, 'meta': resp['meta']}
Пример #10
0
    def create_instance(self, data_defs):
        """Create a report instance with multiple data definition requests.

        :param data_defs: list of DataDef objects
        :return: one ReportInstance object
        """
        if not data_defs:
            msg = 'No data definitions are provided.'
            raise AppResponseException(msg)

        if (any(dd.source.name == 'packets' for dd in data_defs)
                and any(dd.source.name != 'packets' for dd in data_defs)):
            # Two report instance needs to be created, one uses 'npm.reports'
            # service, the other one uses 'npm.probe.reports' service
            # it would create unnecessary complexity to support this case
            # thus report error and let the user to create two separate
            # report instances

            msg = ('Both packets data source and non-packets data source are '
                   'being queried in this report, which is not supported. The '
                   'data source names include {}'.format(', '.join(
                       set([dd.source.name for dd in data_defs]))))
            raise AppResponseException(msg)

        live = all(dd.live for dd in data_defs)

        if not live and any(dd.live for dd in data_defs):
            msg = ('Incompatible DataDefs for report: live and non-live '
                   'cannot be mixed.')
            raise AppResponseException(msg)

        def _create_instance(service_name, data_defs, live):
            config = dict(data_defs=[dd.to_dict() for dd in data_defs],
                          live=live)
            logger.debug("Creating instance with data definitions %s" % config)

            svcdef = self.appresponse.find_service(service_name)
            datarep = svcdef.bind('instances')
            resp = datarep.execute('create', _data=config)

            # XXX sleepwalker bug?  resp is actually an `instances`
            # resource with the data for a single `instance`.  Doing a
            # `.pull()` will fill data with /instances collection instead

            # here we cast result to actual `instance` instance

            report_instance = svcdef.bind('instance', id=resp.data['id'])

            instance = ReportInstance(data=resp.data,
                                      datarep=report_instance,
                                      live=live)
            return instance

        if data_defs[0].source.name == 'packets':
            # Create clip for for capture job sources only
            # Keep the clip till the instance is completed
            if data_defs[0].source.path.startswith(SourceProxy.JOB_PREFIX):
                with self.appresponse.clips.create_clips(data_defs):
                    instance = _create_instance(PACKETS_REPORT_SERVICE_NAME,
                                                data_defs, False)
            else:
                instance = _create_instance(PACKETS_REPORT_SERVICE_NAME,
                                            data_defs, live)
        else:
            instance = _create_instance(GENERAL_REPORT_SERVICE_NAME, data_defs,
                                        live)
        return instance